1 /* GemRB - Infinity Engine Emulator
2 * Copyright (C) 2006 The GemRB Project
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21 #include "ProjectileServer.h"
24 #include "Interface.h"
25 #include "ProjectileMgr.h"
26 #include "SymbolMgr.h"
28 //////////////////////////////////////////////////////////////////////
29 // Construction/Destruction
30 //////////////////////////////////////////////////////////////////////
32 #define MAX_PROJ_IDX 0x1fff
34 ProjectileServer::ProjectileServer()
42 ProjectileServer::~ProjectileServer()
52 Projectile
*ProjectileServer::CreateDefaultProjectile(unsigned int idx
)
54 Projectile
*pro
= new Projectile();
55 //int strlength = (ieByte *) (&pro->Extension)-(ieByte *) (&pro->Type);
56 //memset(&pro->Type, 0, strlength );
57 int strlength
= (ieByte
*) (&pro
->Extension
)-(ieByte
*) (&pro
->Speed
);
58 memset(&pro
->Speed
, 0, strlength
);
60 //take care, this projectile is not freed up by the server
61 if(idx
==(unsigned int) ~0 ) {
65 projectiles
[idx
].projectile
= pro
;
66 pro
->SetIdentifiers(projectiles
[idx
].resname
, idx
);
67 return ReturnCopy(idx
);
70 //this function can return only projectiles listed in projectl.ids
71 Projectile
*ProjectileServer::GetProjectileByName(const ieResRef resname
)
73 if (!core
->IsAvailable(IE_PRO_CLASS_ID
)) {
76 unsigned int idx
=GetHighestProjectileNumber();
78 if (!strnicmp(resname
, projectiles
[idx
].resname
,8) ) {
79 return GetProjectile(idx
);
85 Projectile
*ProjectileServer::GetProjectileByIndex(unsigned int idx
)
87 if (!core
->IsAvailable(IE_PRO_CLASS_ID
)) {
90 if (idx
>=GetHighestProjectileNumber()) {
91 return GetProjectile(0);
94 return GetProjectile(idx
);
97 Projectile
*ProjectileServer::ReturnCopy(unsigned int idx
)
99 Projectile
*pro
= new Projectile();
100 Projectile
*old
= projectiles
[idx
].projectile
;
101 //int strlength = (ieByte *) (&pro->Extension)-(ieByte *) (&pro->Type);
102 //memcpy(&pro->Type, &old->Type, strlength );
103 int strlength
= (ieByte
*) (&pro
->Extension
)-(ieByte
*) (&pro
->Speed
);
104 memcpy(&pro
->Speed
, &old
->Speed
, strlength
);
105 //FIXME: copy extension data too, or don't alter the extension
106 if (old
->Extension
) {
107 pro
->Extension
= old
->Extension
;
109 pro
->SetIdentifiers(projectiles
[idx
].resname
, idx
);
113 Projectile
*ProjectileServer::GetProjectile(unsigned int idx
)
115 if (projectiles
[idx
].projectile
) {
116 return ReturnCopy(idx
);
118 DataStream
* str
= gamedata
->GetResource( projectiles
[idx
].resname
, IE_PRO_CLASS_ID
);
119 PluginHolder
<ProjectileMgr
> sm(IE_PRO_CLASS_ID
);
122 return CreateDefaultProjectile(idx
);
124 if (!sm
->Open( str
, true )) {
125 return CreateDefaultProjectile(idx
);
127 Projectile
*pro
= new Projectile();
128 projectiles
[idx
].projectile
= pro
;
129 pro
->SetIdentifiers(projectiles
[idx
].resname
, idx
);
131 sm
->GetProjectile( pro
);
135 Type
= pro
->Extension
->ExplType
;
140 //fill the spread field according to the hardcoded explosion type
141 res
= GetExplosion(Type
,0);
143 strnuprcpy(pro
->Extension
->Spread
,*res
,sizeof(ieResRef
)-1);
146 //if the hardcoded explosion type has a center animation
147 //override the VVC animation field with it
148 res
= GetExplosion(Type
,1);
150 pro
->Extension
->AFlags
|=PAF_VVC
;
151 strnuprcpy(pro
->Extension
->VVCRes
,*res
,sizeof(ieResRef
)-1);
154 //fill the secondary spread field out
155 res
= GetExplosion(Type
,2);
157 strnuprcpy(pro
->Extension
->Secondary
,*res
,sizeof(ieResRef
)-1);
160 //the explosion sound, used for the first explosion
161 //(overrides an original field)
162 res
= GetExplosion(Type
,3);
164 strnuprcpy(pro
->Extension
->SoundRes
,*res
,sizeof(ieResRef
)-1);
167 //the area sound (used for subsequent explosions)
168 res
= GetExplosion(Type
,4);
170 strnuprcpy(pro
->Extension
->AreaSound
,*res
,sizeof(ieResRef
)-1);
173 //fill the explosion/spread animation flags
174 pro
->Extension
->APFlags
= GetExplosionFlags(Type
);
177 pro
->autofree
= true;
178 return ReturnCopy(idx
);
181 int ProjectileServer::InitExplosion()
183 if (explosioncount
>=0) {
184 return explosioncount
;
187 AutoTable
explist("areapro");
191 unsigned int rows
= (unsigned int) explist
->GetRowCount();
192 //cannot handle 0xff and it is easier to set up the fields
193 //without areapro.2da anyway. So this isn't a restriction
197 explosioncount
= rows
;
198 explosions
= new ExplosionEntry
[rows
];
203 for(i
=0;i
<AP_RESCNT
;i
++) {
204 strnuprcpy(explosions
[rows
].resources
[i
], explist
->QueryField(rows
, i
), 8);
206 //using i so the flags field will always be after the resources
207 explosions
[rows
].flags
= atoi(explist
->QueryField(rows
,i
));
210 return explosioncount
;
213 unsigned int ProjectileServer::PrepareSymbols(Holder
<SymbolMgr
> projlist
) {
214 unsigned int count
= 0;
216 unsigned int rows
= (unsigned int) projlist
->GetSize();
218 unsigned int value
= projlist
->GetValueIndex(rows
);
219 if (value
>MAX_PROJ_IDX
) {
220 //value = MAX_PROJ_IDX;
221 printMessage("ProjectileServer","Too high projectilenumber\n", YELLOW
);
224 if (value
>(unsigned int) count
) {
225 count
= (unsigned int) value
;
232 void ProjectileServer::AddSymbols(Holder
<SymbolMgr
> projlist
) {
233 unsigned int rows
= (unsigned int) projlist
->GetSize();
235 unsigned int value
= projlist
->GetValueIndex(rows
);
236 if (value
>MAX_PROJ_IDX
) {
239 if (value
>= (unsigned int)projectilecount
) {
240 // this should never happen!
241 printMessage("ProjectileServer","Too high projectilenumber while adding projectiles\n", RED
);
244 strnuprcpy(projectiles
[value
].resname
, projlist
->GetStringIndex(rows
), 8);
248 unsigned int ProjectileServer::GetHighestProjectileNumber()
250 if (projectilecount
>=0) {
251 // already read the projectiles
252 return (unsigned int) projectilecount
;
255 // built-in gemrb projectiles and game/mod-provided projectiles
256 unsigned int gemresource
= core
->LoadSymbol("gemprjtl");
257 Holder
<SymbolMgr
> gemprojlist
= core
->GetSymbol(gemresource
);
258 unsigned int resource
= core
->LoadSymbol("projectl");
259 Holder
<SymbolMgr
> projlist
= core
->GetSymbol(resource
);
261 // first, we must calculate how many projectiles we have
263 projectilecount
= PrepareSymbols(gemprojlist
) + 1;
266 unsigned int temp
= PrepareSymbols(projlist
) + 1;
267 if (projectilecount
== -1 || temp
> (unsigned int)projectilecount
)
268 projectilecount
= temp
;
271 // then, allocate space for them all
272 if (projectilecount
== -1) {
273 // no valid projectiles files..
276 projectiles
= new ProjectileEntry
[projectilecount
];
278 // finally, we must read the projectile resrefs
280 AddSymbols(projlist
);
281 core
->DelSymbol(resource
);
283 // gemprojlist is second because it always overrides game/mod-supplied projectiles
285 AddSymbols(gemprojlist
);
286 core
->DelSymbol(gemresource
);
289 return (unsigned int) projectilecount
;
292 //return various flags for the explosion type
293 int ProjectileServer::GetExplosionFlags(unsigned int idx
)
295 if (explosioncount
==-1) {
296 if (InitExplosion()<0) {
297 printMessage("ProjectileServer","Problem with explosions\n", RED
);
301 if (idx
>=(unsigned int) explosioncount
) {
305 return explosions
[idx
].flags
;
308 ieResRef
const *ProjectileServer::GetExplosion(unsigned int idx
, int type
)
310 if (explosioncount
==-1) {
311 if (InitExplosion()<0) {
312 printMessage("ProjectileServer","Problem with explosions\n", RED
);
316 if (idx
>=(unsigned int) explosioncount
) {
319 ieResRef
const *ret
= NULL
;
321 ret
= &explosions
[idx
].resources
[type
];
322 if (ret
&& *ret
[0]=='*') ret
= NULL
;