[+] Added new RadialParticle

[+] Make particles more configurable from Lua
[+] Added 'g' flag for ParseAnimInt to get flag for target unit
[+] Added MissileOffsets array which allows more correct placing for missile's starting point (not from unit's center, but from cannon's hole etc.)
[+] Added CclGetUnitBoolFlag to get unit's bool-flags in Lua
[+] Removed speedup variables (SpeedResourcesHarvest, SpeedResourcesReturn, SpeedBuild, SpeedTrain, SpeedUpgrade, SpeedResearch) into player's code, now speedup could be set individually for each player
[+] Added CUpgradeModifier::ModifyPercent for modifying variables by percent, not by const value.
[+] Added MissileType::Pierce to allow missiles damage everything on their way
[+] Added map preview image generation function for editor (not ready for OpenGL yet)
[+] Added flag for CclCreateMissile to control missile's damage
[*] Missiles now fly into unit's center (according to the comment in code, the old behaviour was to be used for bunkers)
[-] Fixed random number generation code in animations
[-] Fixed "Flushing removed unit" message for boarded units
[-] Fixed unit death into container (happens when unit is temporary)
[-] Fixed land-only restriction for transporters
[-] Fixed "spell-cast" mouse action for non-enemy units (now it's possible to use this action for medics)
[-] Fixed compilation for MSVC9
This commit is contained in:
cybermind 2012-08-08 03:08:27 +06:00
parent 98bc02d104
commit dde984d690
38 changed files with 647 additions and 158 deletions

View file

@ -213,6 +213,7 @@ set(particle_SRCS
src/particle/graphicanimation.cpp
src/particle/chunkparticle.cpp
src/particle/particlemanager.cpp
src/particle/radialparticle.cpp
src/particle/smokeparticle.cpp
src/particle/staticparticle.cpp
)

View file

@ -351,7 +351,7 @@ void COrder_Built::Progress(CUnit &unit, int amount)
Boost(unit, amount, HP_INDEX);
Boost(unit, amount, SHIELD_INDEX);
this->ProgressCounter += amount * SpeedBuild;
this->ProgressCounter += amount * unit.Player->SpeedBuild / SPEEDUP_FACTOR;
UpdateConstructionFrame(unit);
}
@ -359,7 +359,7 @@ void COrder_Built::ProgressHp(CUnit &unit, int amount)
{
Boost(unit, amount, HP_INDEX);
this->ProgressCounter += amount * SpeedBuild;
this->ProgressCounter += amount * unit.Player->SpeedBuild / SPEEDUP_FACTOR;
UpdateConstructionFrame(unit);
}
@ -370,7 +370,7 @@ void COrder_Built::Boost(CUnit &building, int amount, int varIndex) const
const int costs = building.Stats->Costs[TimeCost] * 600;
const int progress = this->ProgressCounter;
const int newProgress = progress + amount * SpeedBuild;
const int newProgress = progress + amount * building.Player->SpeedBuild / SPEEDUP_FACTOR;
const int maxValue = building.Variable[varIndex].Max;
int &currentValue = building.Variable[varIndex].Value;

View file

@ -133,7 +133,7 @@
}
#endif
CPlayer &player = *unit.Player;
player.UpgradeTimers.Upgrades[upgrade.ID] += SpeedResearch;
player.UpgradeTimers.Upgrades[upgrade.ID] += player.SpeedResearch / SPEEDUP_FACTOR;
if (player.UpgradeTimers.Upgrades[upgrade.ID] >= upgrade.Costs[TimeCost]) {
player.Notify(NotifyGreen, unit.tilePos, _("%s: research complete"), type.Name.c_str());
if (&player == ThisPlayer) {

View file

@ -474,7 +474,7 @@ int COrder_Resource::StartGathering(CUnit &unit)
#endif
UnitHeadingFromDeltaXY(unit, this->goalPos - unit.tilePos);
if (resinfo.WaitAtResource) {
this->TimeToHarvest = resinfo.WaitAtResource / SpeedResourcesHarvest[resinfo.ResourceId];
this->TimeToHarvest = resinfo.WaitAtResource / unit.Player->SpeedResourcesHarvest[resinfo.ResourceId] / SPEEDUP_FACTOR;
} else {
this->TimeToHarvest = 1;
}
@ -542,7 +542,7 @@ int COrder_Resource::StartGathering(CUnit &unit)
goal->Resource.Active++;
if (resinfo.WaitAtResource) {
this->TimeToHarvest = resinfo.WaitAtResource / SpeedResourcesHarvest[resinfo.ResourceId];
this->TimeToHarvest = resinfo.WaitAtResource / unit.Player->SpeedResourcesHarvest[resinfo.ResourceId] / SPEEDUP_FACTOR;
} else {
this->TimeToHarvest = 1;
}
@ -674,7 +674,7 @@ int COrder_Resource::GatherResource(CUnit &unit)
while (!this->DoneHarvesting && this->TimeToHarvest < 0) {
//FIXME: rb - how should it look for WaitAtResource == 0
if (resinfo.WaitAtResource) {
this->TimeToHarvest += resinfo.WaitAtResource / SpeedResourcesHarvest[resinfo.ResourceId];
this->TimeToHarvest += resinfo.WaitAtResource / unit.Player->SpeedResourcesHarvest[resinfo.ResourceId] / SPEEDUP_FACTOR;
} else {
this->TimeToHarvest += 1;
}
@ -965,7 +965,7 @@ int COrder_Resource::MoveToDepot(CUnit &unit)
unit.CurrentResource = 0;
if (unit.Wait) {
unit.Wait /= SpeedResourcesReturn[resinfo.ResourceId];
unit.Wait /= unit.Player->SpeedResourcesReturn[resinfo.ResourceId] / SPEEDUP_FACTOR;
if (unit.Wait) {
unit.Wait--;
}

View file

@ -187,7 +187,7 @@ static void AnimateActionTrain(CUnit &unit)
CPlayer &player = *unit.Player;
const CUnitType &nType = *this->Type;
const int cost = nType.Stats[player.Index].Costs[TimeCost];
this->Ticks += SpeedTrain;
this->Ticks += player.SpeedTrain / SPEEDUP_FACTOR;
if (this->Ticks < cost) {
unit.Wait = CYCLES_PER_SECOND / 6;

View file

@ -266,7 +266,7 @@ static void AnimateActionUpgradeTo(CUnit &unit)
const CUnitType &newtype = *this->Type;
const CUnitStats &newstats = newtype.Stats[player.Index];
this->Ticks += SpeedUpgrade;
this->Ticks += player.SpeedUpgrade / SPEEDUP_FACTOR;
if (this->Ticks < newstats.Costs[TimeCost]) {
unit.Wait = CYCLES_PER_SECOND / 6;
return ;

View file

@ -283,6 +283,7 @@ static void HandleBuffs(CUnit &unit, int amount)
unit.Variable[HP_INDEX].Value -= amount;
if (unit.Variable[HP_INDEX].Value <= 0) {
LetUnitDie(unit);
return;
}
}
@ -343,7 +344,7 @@ static void HandleUnitAction(CUnit &unit)
// o Or the order queue should be flushed.
if ((unit.Orders[0]->Action == UnitActionStandGround || unit.Orders[0]->Finished)
&& unit.Orders.size() > 1) {
if (unit.Removed) { // FIXME: johns I see this as an error
if (unit.Removed && unit.Orders[0]->Action != UnitActionBoard) { // FIXME: johns I see this as an error
DebugPrint("Flushing removed unit\n");
// This happens, if building with ALT+SHIFT.
return;

View file

@ -177,7 +177,14 @@ int ParseAnimInt(const CUnit *unit, const char *parseint)
return goal->Variable[index].Value * 100 / goal->Variable[index].Max;
}
return 0;
} else if ((s[0] == 'b') && unit != NULL) { //unit bool flag detected
} else if ((s[0] == 'b' || s[0] == 'g') && unit != NULL) { //unit bool flag detected
if (s[0] == 'g') {
if (unit->CurrentOrder()->HasGoal()) {
goal = unit->CurrentOrder()->GetGoal();
} else {
return 0;
}
}
const int index = UnitTypeVar.BoolFlagNameLookup[cur];// User bool flags
if (index == -1) {
fprintf(stderr, "Bad bool-flag name '%s'\n", cur);
@ -209,10 +216,11 @@ int ParseAnimInt(const CUnit *unit, const char *parseint)
} else if (s[0] == 'r') { //random value
char *next = strchr(cur, '.');
if (next == NULL) {
return SyncRand(atoi(cur));
return SyncRand(atoi(cur) + 1);
} else {
*next = '\0';
return atoi(cur) + SyncRand(atoi(next + 1));
const int min = atoi(cur);
return min + SyncRand(atoi(next + 1) - min + 1);
}
} else if (s[0] == 'l') { //player number
return ParseAnimPlayer(*unit, cur);

View file

@ -99,7 +99,10 @@ static int ParseAnimFlags(CUnit &unit, const char *parseflag)
const int destx = ParseAnimInt(&unit, this->destXStr.c_str());
const int desty = ParseAnimInt(&unit, this->destYStr.c_str());
const int flags = ParseAnimFlags(unit, this->flagsStr.c_str());
const int offsetnum = ParseAnimInt(&unit, this->offsetNumStr.c_str());
const CUnit *goal = flags & ANIM_SM_RELTARGET ? unit.CurrentOrder()->GetGoal() : &unit;
const int dir = ((goal->Direction + NextDirection / 2) & 0xFF) / NextDirection;
const PixelPos moff = goal->Type->MissileOffsets[dir][!offsetnum ? 0 : offsetnum - 1];
PixelPos start;
PixelPos dest;
@ -107,11 +110,11 @@ static int ParseAnimFlags(CUnit &unit, const char *parseflag)
return;
}
if ((flags & ANIM_SM_PIXEL)) {
start.x = goal->tilePos.x * PixelTileSize.x + goal->IX + startx;
start.y = goal->tilePos.y * PixelTileSize.y + goal->IY + starty;
start.x = goal->tilePos.x * PixelTileSize.x + goal->IX + moff.x + startx;
start.y = goal->tilePos.y * PixelTileSize.y + goal->IY + moff.y + starty;
} else {
start.x = (goal->tilePos.x + startx) * PixelTileSize.x + PixelTileSize.x / 2;
start.y = (goal->tilePos.y + starty) * PixelTileSize.y + PixelTileSize.y / 2;
start.x = (goal->tilePos.x + startx) * PixelTileSize.x + PixelTileSize.x / 2 + moff.x;
start.y = (goal->tilePos.y + starty) * PixelTileSize.y + PixelTileSize.y / 2 + moff.y;
}
if ((flags & ANIM_SM_TOTARGET)) {
CUnit *target = goal->CurrentOrder()->GetGoal();
@ -186,6 +189,10 @@ static int ParseAnimFlags(CUnit &unit, const char *parseflag)
begin = std::min(len, str.find_first_not_of(' ', end));
end = std::min(len, str.find(' ', begin));
this->flagsStr.assign(str, begin, end - begin);
begin = std::min(len, str.find_first_not_of(' ', end));
end = std::min(len, str.find(' ', begin));
this->offsetNumStr.assign(str, begin, end - begin);
}
//@}

View file

@ -34,6 +34,8 @@
-- Includes
----------------------------------------------------------------------------*/
#include <png.h>
#include "stratagus.h"
#include "actions.h"
@ -168,6 +170,115 @@ static void LoadStratagusMap(const std::string &smpname, const std::string &mapn
Map.Info.Filename = mapname;
}
// Write a small image of map preview
static void WriteMapPreview(const char *mapname, CMap &map)
{
FILE *fp = fopen(mapname, "wb");
if (fp == NULL) {
return;
}
png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
if (png_ptr == NULL) {
fclose(fp);
return;
}
png_infop info_ptr = png_create_info_struct(png_ptr);
if (info_ptr == NULL) {
fclose(fp);
png_destroy_write_struct(&png_ptr, NULL);
return;
}
if (setjmp(png_jmpbuf(png_ptr))) {
/* If we get here, we had a problem reading the file */
fclose(fp);
png_destroy_write_struct(&png_ptr, &info_ptr);
return;
}
/* set up the output control if you are using standard C streams */
png_init_io(png_ptr, fp);
png_set_IHDR(png_ptr, info_ptr, UI.Minimap.W, UI.Minimap.H, 8,
PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT,
PNG_FILTER_TYPE_DEFAULT);
png_write_info(png_ptr, info_ptr);
if (UseOpenGL) {
unsigned char *pixels = new unsigned char[UI.Minimap.W * UI.Minimap.H * 3];
if (!pixels) {
fprintf(stderr, "Out of memory\n");
exit(1);
}
#ifndef USE_GLES
glReadBuffer(GL_FRONT);
#endif
glReadPixels(UI.Minimap.X, UI.Minimap.Y, UI.Minimap.W, UI.Minimap.H, GL_RGB, GL_UNSIGNED_BYTE, pixels);
for (int i = 0; i < UI.Minimap.H; ++i) {
png_write_row(png_ptr, pixels + (UI.Minimap.H - 1 - i) * UI.Minimap.W * 3);
}
delete[] pixels;
} else {
unsigned char *row = new unsigned char[UI.Minimap.W * 3];
const SDL_PixelFormat *fmt = MinimapSurface->format;
SDL_Surface *preview = SDL_CreateRGBSurface(SDL_SWSURFACE,
UI.Minimap.W, UI.Minimap.H, 32, fmt->Rmask, fmt->Gmask, fmt->Bmask, 0);
SDL_BlitSurface(MinimapSurface, NULL, preview, NULL);
SDL_LockSurface(preview);
SDL_Rect rect;
const unsigned int rectSize = 5;
for (int i = 0; i < PlayerMax - 1; ++i) {
if (Players[i].Type != PlayerNobody) {
rect.x = Players[i].StartPos.x * UI.Minimap.W / map.Info.MapWidth - rectSize / 2;
rect.y = Players[i].StartPos.y * UI.Minimap.H / map.Info.MapHeight - rectSize / 2;
rect.w = rect.h = rectSize;
SDL_FillRect(preview, &rect, Players[i].Color);
}
}
for (int i = 0; i < UI.Minimap.H; ++i) {
switch (preview->format->BytesPerPixel) {
case 1:
for (int j = 0; j < UI.Minimap.W; ++j) {
Uint8 c = ((Uint8 *)preview->pixels)[j + i * UI.Minimap.W];
row[j * 3 + 0] = fmt->palette->colors[c].r;
row[j * 3 + 1] = fmt->palette->colors[c].g;
row[j * 3 + 2] = fmt->palette->colors[c].b;
}
break;
case 3:
memcpy(row, (char *)preview->pixels + i * UI.Minimap.W, UI.Minimap.W * 3);
break;
case 4:
for (int j = 0; j < UI.Minimap.W; ++j) {
Uint32 c = ((Uint32 *)preview->pixels)[j + i * UI.Minimap.W];
row[j * 3 + 0] = ((c & fmt->Rmask) >> fmt->Rshift);
row[j * 3 + 1] = ((c & fmt->Gmask) >> fmt->Gshift);
row[j * 3 + 2] = ((c & fmt->Bmask) >> fmt->Bshift);
}
break;
}
png_write_row(png_ptr, row);
}
delete[] row;
SDL_UnlockSurface(preview);
SDL_FreeSurface(preview);
}
png_write_end(png_ptr, info_ptr);
/* clean up after the write, and free any memory allocated */
png_destroy_write_struct(&png_ptr, &info_ptr);
fclose(fp);
}
// Write the map presentation file
static int WriteMapPresentation(const std::string &mapname, CMap &map, char *)
@ -282,6 +393,7 @@ int WriteMapSetup(const char *mapSetup, CMap &map, int writeTerrain)
}
f->printf("-- place units\n");
f->printf("if (MapUnitsInit ~= nil) then MapUnitsInit() end\n");
for (CUnitManager::Iterator it = UnitManager.begin(); it != UnitManager.end(); ++it) {
CUnit &unit = **it;
f->printf("unit = CreateUnit(\"%s\", %d, {%d, %d})\n",
@ -315,7 +427,9 @@ int WriteMapSetup(const char *mapSetup, CMap &map, int writeTerrain)
int SaveStratagusMap(const std::string &mapName, CMap &map, int writeTerrain)
{
char mapSetup[PATH_MAX];
char *extension;
char previewName[PATH_MAX];
char *setupExtension;
char *previewExtension;
if (!map.Info.MapWidth || !map.Info.MapHeight) {
fprintf(stderr, "%s: invalid Stratagus map\n", mapName.c_str());
@ -323,12 +437,17 @@ int SaveStratagusMap(const std::string &mapName, CMap &map, int writeTerrain)
}
strcpy_s(mapSetup, sizeof(mapSetup), mapName.c_str());
extension = strstr(mapSetup, ".smp");
if (!extension) {
setupExtension = strstr(mapSetup, ".smp");
if (!setupExtension) {
fprintf(stderr, "%s: invalid Statagus map filename\n", mapName.c_str());
}
memcpy(extension, ".sms", 4 * sizeof(char));
strcpy_s(previewName, sizeof(previewName), mapName.c_str());
previewExtension = strstr(previewName, ".smp");
memcpy(previewExtension, ".png\0", 5 * sizeof(char));
WriteMapPreview(previewName, map);
memcpy(setupExtension, ".sms", 4 * sizeof(char));
if (WriteMapPresentation(mapName, map, mapSetup) == -1) {
return -1;
}
@ -910,50 +1029,54 @@ static int CclGetGodMode(lua_State *l)
}
/**
** Set resource harvesting speed.
** Set resource harvesting speed (deprecated).
**
** @param l Lua state.
*/
static int CclSetSpeedResourcesHarvest(lua_State *l)
{
LuaCheckArgs(l, 2);
LuaCheckArgs(l, 3);
const std::string resource = LuaToString(l, 1);
const int player = LuaToNumber(l, 1);
const std::string resource = LuaToString(l, 2);
const int resId = GetResourceIdByName(l, resource.c_str());
SpeedResourcesHarvest[resId] = LuaToNumber(l, 2);
Players[player].SpeedResourcesHarvest[resId] = LuaToNumber(l, 3);
return 0;
}
/**
** Set resource returning speed.
** Set resource returning speed (deprecated).
**
** @param l Lua state.
*/
static int CclSetSpeedResourcesReturn(lua_State *l)
{
LuaCheckArgs(l, 2);
const std::string resource = LuaToString(l, 1);
LuaCheckArgs(l, 3);
const int player = LuaToNumber(l, 1);
const std::string resource = LuaToString(l, 2);
const int resId = GetResourceIdByName(l, resource.c_str());
SpeedResourcesReturn[resId] = LuaToNumber(l, 2);
Players[player].SpeedResourcesReturn[resId] = LuaToNumber(l, 3);
return 0;
}
/**
** Set building speed.
** Set building speed (deprecated).
**
** @param l Lua state.
*/
static int CclSetSpeedBuild(lua_State *l)
{
LuaCheckArgs(l, 1);
SpeedBuild = LuaToNumber(l, 1);
LuaCheckArgs(l, 2);
const int player = LuaToNumber(l, 1);
Players[player].SpeedBuild = LuaToNumber(l, 2);
return 0;
}
/**
** Get building speed.
** Get building speed (deprecated).
**
** @param l Lua state.
**
@ -961,25 +1084,27 @@ static int CclSetSpeedBuild(lua_State *l)
*/
static int CclGetSpeedBuild(lua_State *l)
{
LuaCheckArgs(l, 0);
lua_pushnumber(l, SpeedBuild);
LuaCheckArgs(l, 1);
const int player = LuaToNumber(l, 1);
lua_pushnumber(l, Players[player].SpeedBuild);
return 1;
}
/**
** Set training speed.
** Set training speed (deprecated).
**
** @param l Lua state.
*/
static int CclSetSpeedTrain(lua_State *l)
{
LuaCheckArgs(l, 1);
SpeedTrain = LuaToNumber(l, 1);
LuaCheckArgs(l, 2);
const int player = LuaToNumber(l, 1);
Players[player].SpeedTrain = LuaToNumber(l, 2);
return 0;
}
/**
** Get training speed.
** Get training speed (deprecated).
**
** @param l Lua state.
**
@ -987,58 +1112,60 @@ static int CclSetSpeedTrain(lua_State *l)
*/
static int CclGetSpeedTrain(lua_State *l)
{
LuaCheckArgs(l, 0);
lua_pushnumber(l, SpeedTrain);
LuaCheckArgs(l, 1);
const int player = LuaToNumber(l, 1);
lua_pushnumber(l, Players[player].SpeedTrain);
return 1;
}
/**
** For debug increase upgrading speed.
** For debug increase upgrading speed (deprecated).
**
** @param l Lua state.
*/
static int CclSetSpeedUpgrade(lua_State *l)
{
LuaCheckArgs(l, 1);
SpeedUpgrade = LuaToNumber(l, 1);
LuaCheckArgs(l, 2);
const int player = LuaToNumber(l, 1);
Players[player].SpeedUpgrade = LuaToNumber(l, 2);
lua_pushnumber(l, SpeedUpgrade);
lua_pushnumber(l, Players[player].SpeedUpgrade);
return 1;
}
/**
** For debug increase researching speed.
** For debug increase researching speed (deprecated).
**
** @param l Lua state.
*/
static int CclSetSpeedResearch(lua_State *l)
{
LuaCheckArgs(l, 1);
SpeedResearch = LuaToNumber(l, 1);
LuaCheckArgs(l, 2);
const int player = LuaToNumber(l, 1);
Players[player].SpeedResearch = LuaToNumber(l, 2);
lua_pushnumber(l, SpeedResearch);
lua_pushnumber(l, Players[player].SpeedResearch);
return 1;
}
/**
** For debug increase all speeds.
** For debug increase all speeds (deprecated).
**
** @param l Lua state.
*/
static int CclSetSpeeds(lua_State *l)
{
int i;
int s;
LuaCheckArgs(l, 1);
s = LuaToNumber(l, 1);
for (i = 0; i < MaxCosts; ++i) {
SpeedResourcesHarvest[i] = s;
SpeedResourcesReturn[i] = s;
const int speed = LuaToNumber(l, 1);
for (int i = 0; i < PlayerMax; ++i) {
for (int j = 0; j < MaxCosts; ++j) {
Players[i].SpeedResourcesHarvest[j] = speed;
Players[i].SpeedResourcesReturn[j] = speed;
}
Players[i].SpeedBuild = Players[i].SpeedTrain = Players[i].SpeedUpgrade = Players[i].SpeedResearch = speed;
}
SpeedBuild = SpeedTrain = SpeedUpgrade = SpeedResearch = s;
lua_pushnumber(l, s);
lua_pushnumber(l, speed);
return 1;
}

View file

@ -148,17 +148,6 @@ int SaveGame(const std::string &filename)
file.printf("SetGodMode(%s)\n", GodMode ? "true" : "false");
for (unsigned int i = 0; i < MaxCosts; ++i) {
file.printf("SetSpeedResourcesHarvest(\"%s\", %d)\n",
DefaultResourceNames[i].c_str(), SpeedResourcesHarvest[i]);
file.printf("SetSpeedResourcesReturn(\"%s\", %d)\n",
DefaultResourceNames[i].c_str(), SpeedResourcesReturn[i]);
}
file.printf("SetSpeedBuild(%d)\n", SpeedBuild);
file.printf("SetSpeedTrain(%d)\n", SpeedTrain);
file.printf("SetSpeedUpgrade(%d)\n", SpeedUpgrade);
file.printf("SetSpeedResearch(%d)\n", SpeedResearch);
SaveUnitTypes(file);
SaveUpgrades(file);
SavePlayers(file);

View file

@ -50,6 +50,7 @@ private:
std::string destXStr;
std::string destYStr;
std::string flagsStr;
std::string offsetNumStr;
};
//@}

View file

@ -85,6 +85,15 @@ public:
bool UpdateCache;
};
// Minimap surface with units (for OpenGL)
extern unsigned char *MinimapSurfaceGL;
// Minimap surface with terrain only (for OpenGL)
extern unsigned char *MinimapTerrainSurfaceGL;
// Minimap surface with units (for software)
extern SDL_Surface *MinimapSurface;
// Minimap surface with terrain only (for software)
extern SDL_Surface *MinimapTerrainSurface;
//@}
#endif // !__MINIMAP_H__

View file

@ -373,6 +373,7 @@ public:
bool CanHitOwner; /// missile can hit the owner
bool FriendlyFire; /// missile can't hit own units
bool AlwaysFire; /// missile will always fire (even if target is dead)
bool Pierce; /// missile will hit every unit on his way
int Class; /// missile class
int NumBounces; /// number of bounces

View file

@ -125,7 +125,8 @@ protected:
class CChunkParticle : public CParticle
{
public:
CChunkParticle(CPosition position, Animation *smokeAnimation);
CChunkParticle(CPosition position, Animation *smokeAnimation, Animation *debrisAnimation,
int minVelocity, int maxVelocity, int minTrajectoryAngle);
virtual ~CChunkParticle();
virtual void draw();
@ -139,7 +140,11 @@ protected:
int nextSmokeTicks;
int lifetime;
int age;
int minVelocity;
int maxVelocity;
int minTrajectoryAngle;
float height;
Animation *debrisAnimation;
Animation *smokeAnimation;
struct {
@ -164,6 +169,23 @@ protected:
Animation *puff;
};
class CRadialParticle : public CParticle
{
public:
CRadialParticle(CPosition position, Animation *animation, int maxSpeed);
virtual ~CRadialParticle();
virtual void draw();
virtual void update(int ticks);
virtual CParticle *clone();
protected:
Animation *animation;
float direction;
int speed;
int maxSpeed;
};
class CParticleManager
{

View file

@ -51,6 +51,7 @@
#define STORE_BUILDING 1
#define STORE_BOTH 2
#define SPEEDUP_FACTOR 100
/*----------------------------------------------------------------------------
-- Declarations
----------------------------------------------------------------------------*/
@ -97,6 +98,13 @@ public:
int Incomes[MaxCosts]; /// income of the resources
int Revenue[MaxCosts]; /// income rate of the resources
int SpeedResourcesHarvest[MaxCosts]; /// speed factor for harvesting resources
int SpeedResourcesReturn[MaxCosts]; /// speed factor for returning resources
int SpeedBuild; /// speed factor for building
int SpeedTrain; /// speed factor for training
int SpeedUpgrade; /// speed factor for upgrading
int SpeedResearch; /// speed factor for researching
// FIXME: shouldn't use the constant
int UnitTypesCount[UnitTypeMax]; /// total units of unit-type

View file

@ -59,7 +59,9 @@
#endif
#define snprintf _snprintf
#if !(_MSC_VER >= 1500 && _MSC_VER < 1600)
#define vsnprintf _vsnprintf
#endif
#define unlink _unlink
#define strdup _strdup
#define strcasecmp _stricmp
@ -208,11 +210,6 @@ extern std::string ClickMissile; /// Missile to show when you click
extern std::string DamageMissile; /// Missile to show damage caused
extern std::string MenuRace;
extern int SpeedBuild; /// Speed factor for building
extern int SpeedTrain; /// Speed factor for training
extern int SpeedUpgrade; /// Speed factor for upgrading
extern int SpeedResearch; /// Speed factor for researching
extern bool UseHPForXp; /// true if gain XP by dealing damage, false if by killing.
extern unsigned long GameCycle; /// Game simulation cycle counter

View file

@ -552,6 +552,9 @@ class Mng;
#endif
class LuaCallback;
#define UnitSides 8
#define MaxAttackPos 5
CUnitType *UnitTypeByIdent(const std::string &ident);
enum GroupSelectionMode {
@ -913,15 +916,16 @@ public:
std::string File; /// Sprite files
std::string ShadowFile; /// Shadow file
int Width; /// Sprite width
int Height; /// Sprite height
int OffsetX; /// Sprite horizontal offset
int OffsetY; /// Sprite vertical offset
int DrawLevel; /// Level to Draw UnitType at
int ShadowWidth; /// Shadow sprite width
int ShadowHeight; /// Shadow sprite height
int ShadowOffsetX; /// Shadow horizontal offset
int ShadowOffsetY; /// Shadow vertical offset
int Width; /// Sprite width
int Height; /// Sprite height
int OffsetX; /// Sprite horizontal offset
int OffsetY; /// Sprite vertical offset
int DrawLevel; /// Level to Draw UnitType at
int ShadowWidth; /// Shadow sprite width
int ShadowHeight; /// Shadow sprite height
int ShadowOffsetX; /// Shadow horizontal offset
int ShadowOffsetY; /// Shadow vertical offset
PixelPos MissileOffsets[UnitSides][MaxAttackPos]; /// Attack offsets for missiles
CAnimations *Animations; /// Animation scripts
int StillFrame; /// Still frame

View file

@ -74,16 +74,6 @@ enum CostType {
#define ScoreCost (MaxCosts + 1)
#define ManaResCost (MaxCosts + 2)
/**
** Speed factor for harvesting resources
*/
extern int SpeedResourcesHarvest[MaxCosts];
/**
** Speed factor for returning resources
*/
extern int SpeedResourcesReturn[MaxCosts];
/**
** Default resources for a new player.
*/
@ -187,15 +177,19 @@ public:
class CUpgradeModifier
{
public:
CUpgradeModifier() : UpgradeId(0), ConvertTo(NULL) {
CUpgradeModifier() : UpgradeId(0), ConvertTo(NULL), ModifyPercent(NULL) {
memset(ChangeUnits, 0, sizeof(ChangeUnits));
memset(ChangeUpgrades, 0, sizeof(ChangeUpgrades));
memset(ApplyTo, 0, sizeof(ApplyTo));
}
~CUpgradeModifier() {
delete [] this->ModifyPercent;
}
int UpgradeId; /// used to filter required modifier
CUnitStats Modifier; /// modifier of unit stats.
CUnitStats Modifier; /// modifier of unit stats.
int *ModifyPercent; /// use for percent modifiers
// allow/forbid bitmaps -- used as chars for example:
// `?' -- leave as is, `F' -- forbid, `A' -- allow

View file

@ -66,13 +66,14 @@
-- Variables
----------------------------------------------------------------------------*/
unsigned char *MinimapSurfaceGL;
unsigned char *MinimapTerrainSurfaceGL;
SDL_Surface *MinimapSurface; /// generated minimap
SDL_Surface *MinimapTerrainSurface; /// generated minimap terrain
static GLuint MinimapTexture;
static unsigned char *MinimapSurfaceGL;
static unsigned char *MinimapTerrainSurfaceGL;
static int MinimapTextureWidth;
static int MinimapTextureHeight;
static SDL_Surface *MinimapSurface; /// generated minimap
static SDL_Surface *MinimapTerrainSurface; /// generated minimap terrain
static int *Minimap2MapX; /// fast conversion table
static int *Minimap2MapY; /// fast conversion table

View file

@ -49,6 +49,7 @@
#include "trigger.h"
#include "ui.h"
#include "unit.h"
#include "unit_find.h"
#include "unitsound.h"
#include "unittype.h"
@ -376,7 +377,9 @@ void FireMissile(CUnit &unit, CUnit *goal, const Vec2i &goalPos)
// If Firing from inside a Bunker
CUnit *from = GetFirstContainer(unit);
const PixelPos startPixelPos = Map.TilePosToMapPixelPos_Center(from->tilePos);
const int dir = ((unit.Direction + NextDirection / 2) & 0xFF) / NextDirection;
const PixelPos startPixelPos = Map.TilePosToMapPixelPos_Center(from->tilePos)
+ unit.Type->MissileOffsets[dir][0];
Vec2i dpos;
if (goal) {
@ -391,7 +394,12 @@ void FireMissile(CUnit &unit, CUnit *goal, const Vec2i &goalPos)
}
// Fire to nearest point of the unit!
// If Firing from inside a Bunker
NearestOfUnit(*goal, GetFirstContainer(unit)->tilePos, &dpos);
if (unit.Container) {
NearestOfUnit(*goal, GetFirstContainer(unit)->tilePos, &dpos);
} else {
dpos.x = goal->tilePos.x + goal->Type->TileWidth / 2;
dpos.y = goal->tilePos.y + goal->Type->TileHeight / 2;
}
} else {
dpos = newgoalPos;
// FIXME: Can this be too near??
@ -662,6 +670,14 @@ bool PointToPointMissile(Missile &missile)
missile.Type->SmokeParticle->run();
}
if (missile.Type->Pierce) {
CUnit *unit = UnitOnMapTile(Map.MapPixelPosToTilePos(missile.position), -1);
if (unit && unit->IsAliveOnMap()
&& (missile.Type->FriendlyFire || unit->IsEnemy(*missile.SourceUnit->Player))) {
missile.MissileHit();
}
}
return false;
}
@ -1096,8 +1112,8 @@ MissileType::MissileType(const std::string &ident) :
Ident(ident), Transparency(0), DrawLevel(0),
SpriteFrames(0), NumDirections(0), ChangeVariable(-1), ChangeAmount(0), ChangeMax(false),
CorrectSphashDamage(false), Flip(false), CanHitOwner(false), FriendlyFire(false),
AlwaysFire(false), Class(), NumBounces(0), StartDelay(0), Sleep(0), Speed(0),
Range(0), SplashFactor(0), ImpactParticle(NULL), SmokeParticle(NULL), G(NULL)
AlwaysFire(false), Pierce(false), Class(), NumBounces(0), StartDelay(0), Sleep(0),
Speed(0), Range(0), SplashFactor(0), ImpactParticle(NULL), SmokeParticle(NULL), G(NULL)
{
size.x = 0;
size.y = 0;

View file

@ -40,6 +40,8 @@
#include "missile.h"
#include "luacallback.h"
#include "map.h"
#include "unit_find.h"
/**
** Calculate parabolic trajectories.
@ -86,6 +88,13 @@ static int ParabolicMissile(Missile &missile)
missile.Type->SmokeParticle->pushInteger(position.y);
missile.Type->SmokeParticle->run();
}
if (missile.Type->Pierce) {
CUnit *unit = UnitOnMapTile(Map.MapPixelPosToTilePos(missile.position), -1);
if (unit && unit->IsAliveOnMap()
&& (missile.Type->FriendlyFire || unit->IsEnemy(*missile.SourceUnit->Player))) {
missile.MissileHit();
}
}
return 0;
}

View file

@ -42,6 +42,7 @@
#include "luacallback.h"
#include "map.h"
#include "unit.h"
#include "unit_find.h"
/**
** Handle tracer missile.
@ -76,6 +77,14 @@ static int TracerMissile(Missile &missile)
missile.Type->SmokeParticle->pushInteger(position.y);
missile.Type->SmokeParticle->run();
}
if (missile.Type->Pierce) {
Assert(missile.SourceUnit);
CUnit *unit = UnitOnMapTile(Map.MapPixelPosToTilePos(missile.position), -1);
if (unit && unit->IsAliveOnMap()
&& (missile.Type->FriendlyFire || unit->IsEnemy(*missile.SourceUnit->Player))) {
missile.MissileHit();
}
}
return 0;
}

View file

@ -158,6 +158,8 @@ void MissileType::Load(lua_State *l)
this->CanHitOwner = LuaToBoolean(l, -1);
} else if (!strcmp(value, "AlwaysFire")) {
this->AlwaysFire = LuaToBoolean(l, -1);
} else if (!strcmp(value, "Pierce")) {
this->Pierce = LuaToBoolean(l, -1);
} else if (!strcmp(value, "FriendlyFire")) {
this->FriendlyFire = LuaToBoolean(l, -1);
} else if (!strcmp(value, "SplashFactor")) {
@ -376,7 +378,7 @@ static int CclDefineBurningBuilding(lua_State *l)
*/
static int CclCreateMissile(lua_State *l)
{
LuaCheckArgs(l, 5);
LuaCheckArgs(l, 6);
const std::string name = LuaToString(l, 1);
const MissileType *mtype = MissileTypeByIdent(name);
@ -405,6 +407,7 @@ static int CclCreateMissile(lua_State *l)
const int sourceUnitId = LuaToNumber(l, 4);
const int destUnitId = LuaToNumber(l, 5);
const bool dealDamage = LuaToBoolean(l, 6);
CUnit *sourceUnit = sourceUnitId != -1 ? &UnitManager.GetSlotUnit(sourceUnitId) : NULL;
CUnit *destUnit = destUnitId != -1 ? &UnitManager.GetSlotUnit(destUnitId) : NULL;
@ -419,7 +422,9 @@ static int CclCreateMissile(lua_State *l)
if (!missile) {
return 0;
}
missile->SourceUnit = sourceUnit;
if (dealDamage) {
missile->SourceUnit = sourceUnit;
}
missile->TargetUnit = destUnit;
return 0;
}

View file

@ -44,7 +44,8 @@ static inline float deg2rad(int degrees)
}
CChunkParticle::CChunkParticle(CPosition position, Animation *smokeAnimation) :
CChunkParticle::CChunkParticle(CPosition position, Animation *smokeAnimation, Animation *debrisAnimation,
int minVelocity = 0, int maxVelocity = 400, int minTrajectoryAngle = 77) :
CParticle(position), initialPos(position), nextSmokeTicks(0), age(0),
height(0.f)
{
@ -52,18 +53,20 @@ CChunkParticle::CChunkParticle(CPosition position, Animation *smokeAnimation) :
direction.x = cos(radians);
direction.y = sin(radians);
const int maxVelocity = 400;
initialVelocity = MyRand() % maxVelocity;
this->minVelocity = minVelocity;
this->maxVelocity = maxVelocity;
this->minTrajectoryAngle = minTrajectoryAngle;
this->initialVelocity = this->minVelocity + MyRand() % (this->maxVelocity - this->minVelocity + 1);
this->trajectoryAngle = deg2rad(MyRand() % (90 - this->minTrajectoryAngle) + this->minTrajectoryAngle);
this->lifetime = (int)(1000 * (initialVelocity * sin(trajectoryAngle) / gravity) * 2);
int minTrajectoryAngle = 77;
trajectoryAngle = deg2rad(MyRand() % (90 - minTrajectoryAngle) + minTrajectoryAngle);
lifetime = (int)(1000 * (initialVelocity * sin(trajectoryAngle) / gravity) * 2);
this->smokeAnimation = smokeAnimation->clone();
this->debrisAnimation = debrisAnimation->clone();
}
CChunkParticle::~CChunkParticle()
{
delete debrisAnimation;
delete smokeAnimation;
}
@ -75,10 +78,8 @@ static float calculateScreenPos(float posy, float height)
void CChunkParticle::draw()
{
CPosition screenPos = ParticleManager.getScreenPos(pos);
Uint32 color = ColorBlack;
Video.DrawRectangleClip(color, (int)screenPos.x - 1,
(int)calculateScreenPos(screenPos.y, height) - 1, 2, 2);
screenPos.y = calculateScreenPos(screenPos.y, height);
debrisAnimation->draw(static_cast<int>(screenPos.x), static_cast<int>(screenPos.y));
}
static float getHorizontalPosition(int initialVelocity, float trajectoryAngle, float time)
@ -105,13 +106,20 @@ void CChunkParticle::update(int ticks)
if (age > nextSmokeTicks) {
CPosition p(pos.x, calculateScreenPos(pos.y, height));
Animation *animation = smokeAnimation->clone();
CSmokeParticle *smoke = new CSmokeParticle(p, animation);
Animation *smokeanimation = smokeAnimation->clone();
CSmokeParticle *smoke = new CSmokeParticle(p, smokeanimation);
ParticleManager.add(smoke);
nextSmokeTicks += MyRand() % randSmokeTicks + minSmokeTicks;
}
debrisAnimation->update(ticks);
if (debrisAnimation->isFinished()) {
Animation *debrisanimation = debrisAnimation->clone();
delete debrisAnimation;
debrisAnimation = debrisanimation;
}
float time = age / 1000.f;
float distance = getHorizontalPosition(initialVelocity, trajectoryAngle, time);
@ -124,7 +132,7 @@ void CChunkParticle::update(int ticks)
CParticle *CChunkParticle::clone()
{
return new CChunkParticle(pos, smokeAnimation);
return new CChunkParticle(pos, smokeAnimation, debrisAnimation, minVelocity, maxVelocity, minTrajectoryAngle);
}
//@}

View file

@ -0,0 +1,78 @@
// _________ __ __
// / _____// |_____________ _/ |______ ____ __ __ ______
// \_____ \\ __\_ __ \__ \\ __\__ \ / ___\| | \/ ___/
// / \| | | | \// __ \| | / __ \_/ /_/ > | /\___ |
// /_______ /|__| |__| (____ /__| (____ /\___ /|____//____ >
// \/ \/ \//_____/ \/
// ______________________ ______________________
// T H E W A R B E G I N S
// Stratagus - A free fantasy real time strategy game engine
//
/**@name radialparticle.cpp - The radial particle. */
//
// (c) Copyright 2012 by cybermind
//
// 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; only version 2 of the License.
//
// 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 <math.h>
#include "stratagus.h"
#include "particle.h"
CRadialParticle::CRadialParticle(CPosition position, Animation *animation, int maxSpeed) :
CParticle(position)
{
Assert(animation);
this->animation = animation->clone();
const int speedReduction = 10;
this->direction = (float)(MyRand() % 360);
this->speed = (MyRand() % maxSpeed) / speedReduction;
this->maxSpeed = maxSpeed;
}
CRadialParticle::~CRadialParticle()
{
delete animation;
}
void CRadialParticle::draw()
{
CPosition screenPos = ParticleManager.getScreenPos(pos);
animation->draw(static_cast<int>(screenPos.x), static_cast<int>(screenPos.y));
}
void CRadialParticle::update(int ticks)
{
this->pos.x += this->speed * sin(this->direction);
this->pos.y += this->speed * cos(this->direction);
animation->update(ticks);
if (animation->isFinished()) {
destroy();
}
}
CParticle *CRadialParticle::clone()
{
CParticle *p = new CRadialParticle(pos, animation, maxSpeed);
return p;
}
//@}

View file

@ -36,8 +36,6 @@
#include "stratagus.h"
#include "iolib.h"
#include "iocompat.h"
#include "map.h"
#include "util.h"
@ -48,6 +46,8 @@
#include <fcntl.h>
#endif
#include "iolib.h"
#include <zlib.h>
/*----------------------------------------------------------------------------

View file

@ -512,6 +512,27 @@ void CPlayer::Save(CFile &file) const
file.printf("\n \"total-razings\", %d,", p.TotalRazings);
file.printf("\n \"total-kills\", %d,", p.TotalKills);
file.printf("\n \"speed-resource-harvest\", {");
for (int j = 0; j < MaxCosts; ++j) {
if (j) {
file.printf(" ");
}
file.printf("%d,", p.SpeedResourcesHarvest[j]);
}
file.printf("},");
file.printf("\n \"speed-resource-return\", {");
for (int j = 0; j < MaxCosts; ++j) {
if (j) {
file.printf(" ");
}
file.printf("%d,", p.SpeedResourcesReturn[j]);
}
file.printf("},");
file.printf("\n \"speed-build\", %d,", p.SpeedBuild);
file.printf("\n \"speed-train\", %d,", p.SpeedTrain);
file.printf("\n \"speed-upgrade\", %d,", p.SpeedUpgrade);
file.printf("\n \"speed-research\", %d,", p.SpeedResearch);
Uint8 r, g, b;
SDL_GetRGB(p.Color, TheScreen->format, &r, &g, &b);
@ -739,6 +760,14 @@ void CPlayer::Clear()
TotalKills = 0;
Color = 0;
UpgradeTimers.Clear();
for (int i = 0; i < MaxCosts; ++i) {
SpeedResourcesHarvest[i] = SPEEDUP_FACTOR;
SpeedResourcesReturn[i] = SPEEDUP_FACTOR;
}
SpeedBuild = SPEEDUP_FACTOR;
SpeedTrain = SPEEDUP_FACTOR;
SpeedUpgrade = SPEEDUP_FACTOR;
SpeedResearch = SPEEDUP_FACTOR;
}

View file

@ -303,6 +303,40 @@ void CPlayer::Load(lua_State *l)
this->TotalResources[k] = LuaToNumber(l, -1);
lua_pop(l, 1);
}
} else if (!strcmp(value, "speed-resource-harvest")) {
if (!lua_istable(l, j + 1)) {
LuaError(l, "incorrect argument");
}
const int subargs = lua_rawlen(l, j + 1);
if (subargs != MaxCosts) {
LuaError(l, "Wrong number of speed-resource-harvest: %d" _C_ subargs);
}
for (int k = 0; k < subargs; ++k) {
lua_rawgeti(l, j + 1, k + 1);
this->SpeedResourcesHarvest[k] = LuaToNumber(l, -1);
lua_pop(l, 1);
}
} else if (!strcmp(value, "speed-resource-return")) {
if (!lua_istable(l, j + 1)) {
LuaError(l, "incorrect argument");
}
const int subargs = lua_rawlen(l, j + 1);
if (subargs != MaxCosts) {
LuaError(l, "Wrong number of speed-resource-harvest: %d" _C_ subargs);
}
for (int k = 0; k < subargs; ++k) {
lua_rawgeti(l, j + 1, k + 1);
this->SpeedResourcesReturn[k] = LuaToNumber(l, -1);
lua_pop(l, 1);
}
} else if (!strcmp(value, "speed-build")) {
this->SpeedBuild = LuaToNumber(l, j + 1);
} else if (!strcmp(value, "speed-train")) {
this->SpeedTrain = LuaToNumber(l, j + 1);
} else if (!strcmp(value, "speed-upgrade")) {
this->SpeedUpgrade = LuaToNumber(l, j + 1);
} else if (!strcmp(value, "speed-research")) {
this->SpeedResearch = LuaToNumber(l, j + 1);
} else if (!strcmp(value, "color")) {
if (!lua_istable(l, j + 1) || lua_rawlen(l, j + 1) != 3) {
LuaError(l, "incorrect argument");
@ -785,6 +819,32 @@ static int CclGetPlayerData(lua_State *l)
} else if (!strcmp(data, "TotalKills")) {
lua_pushnumber(l, p->TotalKills);
return 1;
} else if (!strcmp(data, "SpeedResourcesHarvest")) {
LuaCheckArgs(l, 3);
const std::string res = LuaToString(l, 3);
const int resId = GetResourceIdByName(l, res.c_str());
lua_pushnumber(l, p->SpeedResourcesHarvest[resId]);
return 1;
} else if (!strcmp(data, "SpeedResourcesReturn")) {
LuaCheckArgs(l, 3);
const std::string res = LuaToString(l, 3);
const int resId = GetResourceIdByName(l, res.c_str());
lua_pushnumber(l, p->SpeedResourcesReturn[resId]);
return 1;
} else if (!strcmp(data, "SpeedBuild")) {
lua_pushnumber(l, p->SpeedBuild);
return 1;
} else if (!strcmp(data, "SpeedTrain")) {
lua_pushnumber(l, p->SpeedTrain);
return 1;
} else if (!strcmp(data, "SpeedUpgrade")) {
lua_pushnumber(l, p->SpeedUpgrade);
return 1;
} else if (!strcmp(data, "SpeedResearch")) {
lua_pushnumber(l, p->SpeedResearch);
return 1;
} else {
LuaError(l, "Invalid field: %s" _C_ data);
}
@ -858,7 +918,7 @@ static int CclSetPlayerData(lua_State *l)
} else if (!strcmp(data, "TotalBuildings")) {
p->TotalBuildings = LuaToNumber(l, 3);
} else if (!strcmp(data, "TotalResources")) {
LuaCheckArgs(l, 3);
LuaCheckArgs(l, 4);
const std::string res = LuaToString(l, 3);
const int resId = GetResourceIdByName(l, res.c_str());
@ -867,6 +927,26 @@ static int CclSetPlayerData(lua_State *l)
p->TotalRazings = LuaToNumber(l, 3);
} else if (!strcmp(data, "TotalKills")) {
p->TotalKills = LuaToNumber(l, 3);
} else if (!strcmp(data, "SpeedResourcesHarvest")) {
LuaCheckArgs(l, 3);
const std::string res = LuaToString(l, 3);
const int resId = GetResourceIdByName(l, res.c_str());
p->SpeedResourcesHarvest[resId] = LuaToNumber(l, 4);
} else if (!strcmp(data, "SpeedResourcesReturn")) {
LuaCheckArgs(l, 3);
const std::string res = LuaToString(l, 3);
const int resId = GetResourceIdByName(l, res.c_str());
p->SpeedResourcesReturn[resId] = LuaToNumber(l, 4);
} else if (!strcmp(data, "SpeedBuild")) {
p->SpeedBuild = LuaToNumber(l, 3);
} else if (!strcmp(data, "SpeedTrain")) {
p->SpeedTrain = LuaToNumber(l, 3);
} else if (!strcmp(data, "SpeedUpgrade")) {
p->SpeedTrain = LuaToNumber(l, 3);
} else if (!strcmp(data, "SpeedResearch")) {
p->SpeedResearch = LuaToNumber(l, 3);
} else {
LuaError(l, "Invalid field: %s" _C_ data);
}

View file

@ -281,17 +281,6 @@ std::string CliMapName; /// Filename of the map given on the command li
static std::vector<gcn::Container *> Containers;
std::string MenuRace;
/*----------------------------------------------------------------------------
-- Speedups FIXME: Move to some other more logic place
----------------------------------------------------------------------------*/
int SpeedResourcesHarvest[MaxCosts]; /// speed factor for harvesting resources
int SpeedResourcesReturn[MaxCosts]; /// speed factor for returning resources
int SpeedBuild = 1; /// speed factor for building
int SpeedTrain = 1; /// speed factor for training
int SpeedUpgrade = 1; /// speed factor for upgrading
int SpeedResearch = 1; /// speed factor for researching
/*============================================================================
== DISPLAY
============================================================================*/

View file

@ -27,11 +27,19 @@ public:
class CChunkParticle : public CParticle
{
public:
CChunkParticle(CPosition position, Animation *smokeAnimation);
CChunkParticle(CPosition position, Animation *smokeAnimation, Animation *debrisAnimation, int minVelocity = 0, int maxVelocity = 400, int minTrajectoryAngle = 77);
};
class CSmokeParticle : public CParticle
{
public:
CSmokeParticle(CPosition position, Animation *animation);
};
class CRadialParticle : public CParticle
{
public:
CRadialParticle(CPosition position, Animation *smokeAnimation, int maxSpeed);
};
class CParticleManager

View file

@ -43,6 +43,13 @@ class CPlayer
int TotalRazings;
int TotalKills;
int SpeedResourcesHarvest[MaxCosts];
int SpeedResourcesReturn[MaxCosts];
int SpeedBuild;
int SpeedTrain;
int SpeedUpgrade;
int SpeedResearch;
CUnit& GetUnit(int index) const;
int GetUnitCount() const;

View file

@ -278,7 +278,7 @@ static void DoRightButton_Attack(CUnit &unit, CUnit *dest, const Vec2i &pos, int
const int action = type.MouseAction;
if (dest != NULL && unit.CurrentAction() != UnitActionBuilt) {
if (unit.IsEnemy(*dest)) {
if (action == MouseActionSpellCast || unit.IsEnemy(*dest)) {
dest->Blink = 4;
if (!acknowledged) {
PlayUnitSound(unit, VoiceAttack);

View file

@ -990,6 +990,31 @@ static int CclGetUnits(lua_State *l)
return 1;
}
/**
**
** Get the value of the unit bool-flag.
**
** @param l Lua state.
**
** @return The value of the bool-flag of the unit.
*/
static int CclGetUnitBoolFlag(lua_State *l)
{
LuaCheckArgs(l, 2);
lua_pushvalue(l, 1);
const CUnit *unit = CclGetUnit(l);
lua_pop(l, 1);
const char *const value = LuaToString(l, 2);
int index = UnitTypeVar.BoolFlagNameLookup[value];// User bool flags
if (index == -1) {
LuaError(l, "Bad bool-flag name '%s'\n" _C_ value);
}
lua_pushboolean(l, unit->Type->BoolFlag[index].value);
return 1;
}
/**
** Get the value of the unit variable.
**
@ -1130,6 +1155,7 @@ void UnitCclRegister()
lua_register(Lua, "GetUnits", CclGetUnits);
// unit member access functions
lua_register(Lua, "GetUnitBoolFlag", CclGetUnitBoolFlag);
lua_register(Lua, "GetUnitVariable", CclGetUnitVariable);
lua_register(Lua, "SetUnitVariable", CclSetUnitVariable);

View file

@ -639,6 +639,31 @@ static int CclDefineUnitType(lua_State *l)
} else {
LuaError(l, "Unsupported Type: %s" _C_ value);
}
} else if (!strcmp(value, "MissileOffsets")) {
if (!lua_istable(l, -1)) {
LuaError(l, "incorrect argument");
}
const int subargs = lua_rawlen(l, -1);
for (int k = 0; k < subargs; ++k) {
lua_rawgeti(l, -1, k + 1);
if (!lua_istable(l, -1) || lua_rawlen(l, -1) != UnitSides) {
LuaError(l, "incorrect argument");
}
for (int m = 0; m < UnitSides; ++m) {
lua_rawgeti(l, -1, m + 1);
if (!lua_istable(l, -1) || lua_rawlen(l, -1) != 2) {
LuaError(l, "incorrect argument");
}
lua_rawgeti(l, -1, 1);
type->MissileOffsets[m][k].x = LuaToNumber(l, -1);
lua_pop(l, 1);
lua_rawgeti(l, -1, 2);
type->MissileOffsets[m][k].y = LuaToNumber(l, -1);
lua_pop(l, 1);
lua_pop(l, 1);
}
lua_pop(l, 1);
}
} else if (!strcmp(value, "Impact")) {
if (!lua_istable(l, -1)) {
LuaError(l, "incorrect argument");

View file

@ -477,7 +477,7 @@ void CUnit::Init()
void CUnit::Release(bool final)
{
if (Type == NULL) {
DebugPrint("unit already free");
DebugPrint("unit already free\n");
return;
}
Assert(Orders.size() == 1);
@ -492,6 +492,9 @@ void CUnit::Release(bool final)
Destroyed = 1; // mark as destroyed
if (Container && !final) {
if (Boarded) {
Container->BoardCount--;
}
MapUnmarkUnitSight(*this);
RemoveUnitFromContainer(*this);
}
@ -2938,10 +2941,7 @@ int CanTransport(const CUnit &transporter, const CUnit &unit)
if (transporter.BoardCount >= transporter.Type->MaxOnBoard) { // full
return 0;
}
// FIXME: remove UnitTypeLand requirement
if (unit.Type->UnitType != UnitTypeLand) {
return 0;
}
// Can transport only allied unit.
// FIXME : should be parametrable.
if (!transporter.IsTeamed(unit)) {

View file

@ -165,6 +165,7 @@ CUnitType::CUnitType() :
memset(ResInfo, 0, sizeof(ResInfo));
memset(&NeutralMinimapColorRGB, 0, sizeof(NeutralMinimapColorRGB));
memset(ImproveIncomes, 0, sizeof(ImproveIncomes));
memset(MissileOffsets, 0, sizeof(MissileOffsets));
}
CUnitType::~CUnitType()

View file

@ -252,6 +252,8 @@ static int CclDefineModifier(lua_State *l)
memset(um->ChangeUpgrades, '?', sizeof(um->ChangeUpgrades));
memset(um->ApplyTo, '?', sizeof(um->ApplyTo));
um->Modifier.Variables = new CVariable[UnitTypeVar.GetNumberVariable()];
um->ModifyPercent = new int[UnitTypeVar.GetNumberVariable()];
memset(um->ModifyPercent, 0, UnitTypeVar.GetNumberVariable() * sizeof(int));
um->UpgradeId = UpgradeIdByIdent(LuaToString(l, 1));
@ -338,17 +340,28 @@ static int CclDefineModifier(lua_State *l)
} else {
int index = UnitTypeVar.VariableNameLookup[key]; // variable index;
if (index != -1) {
lua_rawgeti(l, j + 1, 2);
if (lua_istable(l, -1)) {
DefineVariableField(l, um->Modifier.Variables + index, -1);
} else if (lua_isnumber(l, -1)) {
um->Modifier.Variables[index].Enable = 1;
um->Modifier.Variables[index].Value = LuaToNumber(l, -1);
um->Modifier.Variables[index].Max = LuaToNumber(l, -1);
if (lua_rawlen(l, j + 1) == 3) {
lua_rawgeti(l, j + 1, 3);
const char *value = LuaToString(l, -1);
lua_pop(l, 1);
if (!strcmp(value, "Percent")) {
lua_rawgeti(l, j + 1, 2);
um->ModifyPercent[index] = LuaToNumber(l, -1);
lua_pop(l, 1);
}
} else {
LuaError(l, "bad argument type for '%s'\n" _C_ key);
lua_rawgeti(l, j + 1, 2);
if (lua_istable(l, -1)) {
DefineVariableField(l, um->Modifier.Variables + index, -1);
} else if (lua_isnumber(l, -1)) {
um->Modifier.Variables[index].Enable = 1;
um->Modifier.Variables[index].Value = LuaToNumber(l, -1);
um->Modifier.Variables[index].Max = LuaToNumber(l, -1);
} else {
LuaError(l, "bad argument type for '%s'\n" _C_ key);
}
lua_pop(l, 1);
}
lua_pop(l, 1);
} else {
LuaError(l, "wrong tag: %s" _C_ key);
}
@ -583,19 +596,28 @@ static void ApplyUpgradeModifier(CPlayer &player, const CUpgradeModifier *um)
for (unsigned int j = 0; j < UnitTypeVar.GetNumberVariable(); j++) {
varModified |= um->Modifier.Variables[j].Value
| um->Modifier.Variables[j].Max
| um->Modifier.Variables[j].Increase;
stat.Variables[j].Value += um->Modifier.Variables[j].Value;
| um->Modifier.Variables[j].Increase
| um->Modifier.Variables[j].Enable
| um->ModifyPercent[j];
stat.Variables[j].Enable = um->Modifier.Variables[j].Enable;
if (um->ModifyPercent[j]) {
stat.Variables[j].Value += stat.Variables[j].Value * um->ModifyPercent[j] / 100;
stat.Variables[j].Max += stat.Variables[j].Max * um->ModifyPercent[j] / 100;
} else {
stat.Variables[j].Value += um->Modifier.Variables[j].Value;
stat.Variables[j].Max += um->Modifier.Variables[j].Max;
stat.Variables[j].Increase += um->Modifier.Variables[j].Increase;
}
if (stat.Variables[j].Value < 0) {
stat.Variables[j].Value = 0;
}
stat.Variables[j].Max += um->Modifier.Variables[j].Max;
if (stat.Variables[j].Max < 0) {
stat.Variables[j].Max = 0;
}
if (stat.Variables[j].Value > stat.Variables[j].Max) {
stat.Variables[j].Value = stat.Variables[j].Max;
}
stat.Variables[j].Increase += um->Modifier.Variables[j].Increase;
}
// And now modify ingame units
@ -610,7 +632,15 @@ static void ApplyUpgradeModifier(CPlayer &player, const CUpgradeModifier *um)
continue;
}
for (unsigned int j = 0; j < UnitTypeVar.GetNumberVariable(); j++) {
unit.Variable[j].Value += um->Modifier.Variables[j].Value;
unit.Variable[j].Enable = um->Modifier.Variables[j].Enable;
if (um->ModifyPercent[j]) {
unit.Variable[j].Value += unit.Variable[j].Value * um->ModifyPercent[j] / 100;
unit.Variable[j].Max += unit.Variable[j].Max * um->ModifyPercent[j] / 100;
} else {
unit.Variable[j].Value += um->Modifier.Variables[j].Value;
unit.Variable[j].Increase += um->Modifier.Variables[j].Increase;
}
if (unit.Variable[j].Value < 0) {
unit.Variable[j].Value = 0;
}
@ -621,7 +651,6 @@ static void ApplyUpgradeModifier(CPlayer &player, const CUpgradeModifier *um)
if (unit.Variable[j].Value > unit.Variable[j].Max) {
unit.Variable[j].Value = unit.Variable[j].Max;
}
unit.Variable[j].Increase += um->Modifier.Variables[j].Increase;
}
}
}