2006-02-24 04:48:15 +00:00
|
|
|
/*
|
|
|
|
** thingdef.cpp
|
|
|
|
**
|
|
|
|
** Actor definitions
|
|
|
|
**
|
|
|
|
**---------------------------------------------------------------------------
|
2006-06-11 01:37:00 +00:00
|
|
|
** Copyright 2002-2006 Christoph Oelckers
|
|
|
|
** Copyright 2004-2006 Randy Heit
|
2006-02-24 04:48:15 +00:00
|
|
|
** All rights reserved.
|
|
|
|
**
|
|
|
|
** Redistribution and use in source and binary forms, with or without
|
|
|
|
** modification, are permitted provided that the following conditions
|
|
|
|
** are met:
|
|
|
|
**
|
|
|
|
** 1. Redistributions of source code must retain the above copyright
|
|
|
|
** notice, this list of conditions and the following disclaimer.
|
|
|
|
** 2. Redistributions in binary form must reproduce the above copyright
|
|
|
|
** notice, this list of conditions and the following disclaimer in the
|
|
|
|
** documentation and/or other materials provided with the distribution.
|
|
|
|
** 3. The name of the author may not be used to endorse or promote products
|
|
|
|
** derived from this software without specific prior written permission.
|
|
|
|
** 4. When not used as part of ZDoom or a ZDoom derivative, this code will be
|
|
|
|
** covered by 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 SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
|
|
|
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
|
|
|
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
|
|
|
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
|
|
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
|
|
|
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
|
|
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
|
|
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
|
|
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
|
|
|
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
**---------------------------------------------------------------------------
|
|
|
|
**
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "gi.h"
|
|
|
|
#include "actor.h"
|
|
|
|
#include "info.h"
|
|
|
|
#include "sc_man.h"
|
|
|
|
#include "tarray.h"
|
|
|
|
#include "w_wad.h"
|
|
|
|
#include "templates.h"
|
|
|
|
#include "r_defs.h"
|
|
|
|
#include "r_draw.h"
|
|
|
|
#include "a_pickups.h"
|
|
|
|
#include "s_sound.h"
|
|
|
|
#include "cmdlib.h"
|
|
|
|
#include "p_lnspec.h"
|
|
|
|
#include "p_enemy.h"
|
|
|
|
#include "a_action.h"
|
|
|
|
#include "decallib.h"
|
|
|
|
#include "m_random.h"
|
|
|
|
#include "autosegs.h"
|
|
|
|
#include "i_system.h"
|
|
|
|
#include "p_local.h"
|
|
|
|
#include "p_effect.h"
|
|
|
|
#include "v_palette.h"
|
|
|
|
#include "doomerrors.h"
|
|
|
|
#include "a_doomglobal.h"
|
2006-03-12 22:04:49 +00:00
|
|
|
#include "a_hexenglobal.h"
|
2006-02-24 04:48:15 +00:00
|
|
|
#include "a_weaponpiece.h"
|
|
|
|
#include "p_conversation.h"
|
2006-05-06 03:25:12 +00:00
|
|
|
#include "v_text.h"
|
2006-04-15 15:00:29 +00:00
|
|
|
#include "thingdef.h"
|
2006-08-17 09:54:42 +00:00
|
|
|
#include "a_sharedglobal.h"
|
2006-02-24 04:48:15 +00:00
|
|
|
|
|
|
|
|
2006-05-10 02:40:43 +00:00
|
|
|
const PClass *QuestItemClasses[31];
|
2006-05-07 00:27:22 +00:00
|
|
|
|
2006-02-24 04:48:15 +00:00
|
|
|
|
|
|
|
extern TArray<FActorInfo *> Decorations;
|
|
|
|
|
|
|
|
// allow decal specifications in DECORATE. Decals are loaded after DECORATE so the names must be stored here.
|
|
|
|
TArray<char*> DecalNames;
|
|
|
|
// all state parameters
|
2006-05-10 15:07:14 +00:00
|
|
|
TArray<int> StateParameters;
|
2006-11-05 21:46:28 +00:00
|
|
|
TArray<int> JumpParameters;
|
2006-02-24 04:48:15 +00:00
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
// List of all flags
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
2006-04-12 03:03:58 +00:00
|
|
|
// [RH] Keep GCC quiet by not using offsetof on Actor types.
|
2006-04-13 02:01:40 +00:00
|
|
|
#define DEFINE_FLAG(prefix, name, type, variable) { prefix##_##name, #name, (int)(size_t)&((type*)1)->variable - 1 }
|
|
|
|
#define DEFINE_FLAG2(symbol, name, type, variable) { symbol, #name, (int)(size_t)&((type*)1)->variable - 1 }
|
2006-02-24 04:48:15 +00:00
|
|
|
|
|
|
|
struct flagdef
|
|
|
|
{
|
|
|
|
int flagbit;
|
|
|
|
const char *name;
|
|
|
|
int structoffset;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
static flagdef ActorFlags[]=
|
|
|
|
{
|
|
|
|
DEFINE_FLAG(MF, SOLID, AActor, flags),
|
|
|
|
DEFINE_FLAG(MF, SHOOTABLE, AActor, flags),
|
|
|
|
DEFINE_FLAG(MF, NOSECTOR, AActor, flags),
|
|
|
|
DEFINE_FLAG(MF, NOBLOCKMAP, AActor, flags),
|
|
|
|
DEFINE_FLAG(MF, AMBUSH, AActor, flags),
|
|
|
|
DEFINE_FLAG(MF, JUSTHIT, AActor, flags),
|
|
|
|
DEFINE_FLAG(MF, JUSTATTACKED, AActor, flags),
|
|
|
|
DEFINE_FLAG(MF, SPAWNCEILING, AActor, flags),
|
|
|
|
DEFINE_FLAG(MF, NOGRAVITY, AActor, flags),
|
|
|
|
DEFINE_FLAG(MF, DROPOFF, AActor, flags),
|
|
|
|
DEFINE_FLAG(MF, NOCLIP, AActor, flags),
|
|
|
|
DEFINE_FLAG(MF, FLOAT, AActor, flags),
|
|
|
|
DEFINE_FLAG(MF, TELEPORT, AActor, flags),
|
|
|
|
DEFINE_FLAG(MF, MISSILE, AActor, flags),
|
|
|
|
DEFINE_FLAG(MF, DROPPED, AActor, flags),
|
|
|
|
DEFINE_FLAG(MF, SHADOW, AActor, flags),
|
|
|
|
DEFINE_FLAG(MF, NOBLOOD, AActor, flags),
|
|
|
|
DEFINE_FLAG(MF, CORPSE, AActor, flags),
|
|
|
|
DEFINE_FLAG(MF, INFLOAT, AActor, flags),
|
|
|
|
DEFINE_FLAG(MF, COUNTKILL, AActor, flags),
|
|
|
|
DEFINE_FLAG(MF, COUNTITEM, AActor, flags),
|
|
|
|
DEFINE_FLAG(MF, SKULLFLY, AActor, flags),
|
|
|
|
DEFINE_FLAG(MF, NOTDMATCH, AActor, flags),
|
2006-11-25 12:25:05 +00:00
|
|
|
DEFINE_FLAG(MF, SPAWNSOUNDSOURCE, AActor, flags),
|
2006-02-24 04:48:15 +00:00
|
|
|
DEFINE_FLAG(MF, FRIENDLY, AActor, flags),
|
|
|
|
DEFINE_FLAG(MF, NOLIFTDROP, AActor, flags),
|
|
|
|
DEFINE_FLAG(MF, STEALTH, AActor, flags),
|
|
|
|
DEFINE_FLAG(MF, ICECORPSE, AActor, flags),
|
|
|
|
DEFINE_FLAG2(MF2_LOGRAV, LOWGRAVITY, AActor, flags2),
|
|
|
|
DEFINE_FLAG(MF2, WINDTHRUST, AActor, flags2),
|
|
|
|
DEFINE_FLAG(MF2, HERETICBOUNCE , AActor, flags2),
|
2006-11-27 00:01:30 +00:00
|
|
|
DEFINE_FLAG(MF2, BLASTED, AActor, flags2),
|
2006-02-24 04:48:15 +00:00
|
|
|
DEFINE_FLAG(MF2, FLOORCLIP, AActor, flags2),
|
|
|
|
DEFINE_FLAG(MF2, SPAWNFLOAT, AActor, flags2),
|
|
|
|
DEFINE_FLAG(MF2, NOTELEPORT, AActor, flags2),
|
|
|
|
DEFINE_FLAG2(MF2_RIP, RIPPER, AActor, flags2),
|
|
|
|
DEFINE_FLAG(MF2, PUSHABLE, AActor, flags2),
|
|
|
|
DEFINE_FLAG2(MF2_SLIDE, SLIDESONWALLS, AActor, flags2),
|
|
|
|
DEFINE_FLAG2(MF2_PASSMOBJ, CANPASS, AActor, flags2),
|
|
|
|
DEFINE_FLAG(MF2, CANNOTPUSH, AActor, flags2),
|
|
|
|
DEFINE_FLAG(MF2, THRUGHOST, AActor, flags2),
|
|
|
|
DEFINE_FLAG(MF2, BOSS, AActor, flags2),
|
|
|
|
DEFINE_FLAG2(MF2_NODMGTHRUST, NODAMAGETHRUST, AActor, flags2),
|
2006-11-29 10:03:35 +00:00
|
|
|
DEFINE_FLAG(MF2, DONTTRANSLATE, AActor, flags2),
|
2006-02-24 04:48:15 +00:00
|
|
|
DEFINE_FLAG(MF2, TELESTOMP, AActor, flags2),
|
|
|
|
DEFINE_FLAG(MF2, FLOATBOB, AActor, flags2),
|
|
|
|
DEFINE_FLAG(MF2, HEXENBOUNCE, AActor, flags2),
|
|
|
|
DEFINE_FLAG(MF2, DOOMBOUNCE, AActor, flags2),
|
|
|
|
DEFINE_FLAG2(MF2_IMPACT, ACTIVATEIMPACT, AActor, flags2),
|
|
|
|
DEFINE_FLAG2(MF2_PUSHWALL, CANPUSHWALLS, AActor, flags2),
|
|
|
|
DEFINE_FLAG2(MF2_MCROSS, ACTIVATEMCROSS, AActor, flags2),
|
|
|
|
DEFINE_FLAG2(MF2_PCROSS, ACTIVATEPCROSS, AActor, flags2),
|
|
|
|
DEFINE_FLAG(MF2, CANTLEAVEFLOORPIC, AActor, flags2),
|
|
|
|
DEFINE_FLAG(MF2, NONSHOOTABLE, AActor, flags2),
|
|
|
|
DEFINE_FLAG(MF2, INVULNERABLE, AActor, flags2),
|
|
|
|
DEFINE_FLAG(MF2, DORMANT, AActor, flags2),
|
|
|
|
DEFINE_FLAG(MF2, SEEKERMISSILE, AActor, flags2),
|
|
|
|
DEFINE_FLAG(MF2, REFLECTIVE, AActor, flags2),
|
|
|
|
DEFINE_FLAG(MF3, FLOORHUGGER, AActor, flags3),
|
|
|
|
DEFINE_FLAG(MF3, CEILINGHUGGER, AActor, flags3),
|
|
|
|
DEFINE_FLAG(MF3, NORADIUSDMG, AActor, flags3),
|
|
|
|
DEFINE_FLAG(MF3, GHOST, AActor, flags3),
|
|
|
|
DEFINE_FLAG(MF3, ALWAYSPUFF, AActor, flags3),
|
|
|
|
DEFINE_FLAG(MF3, DONTSPLASH, AActor, flags3),
|
|
|
|
DEFINE_FLAG(MF3, DONTOVERLAP, AActor, flags3),
|
|
|
|
DEFINE_FLAG(MF3, DONTMORPH, AActor, flags3),
|
|
|
|
DEFINE_FLAG(MF3, DONTSQUASH, AActor, flags3),
|
|
|
|
DEFINE_FLAG(MF3, FULLVOLACTIVE, AActor, flags3),
|
|
|
|
DEFINE_FLAG(MF3, ISMONSTER, AActor, flags3),
|
|
|
|
DEFINE_FLAG(MF3, SKYEXPLODE, AActor, flags3),
|
|
|
|
DEFINE_FLAG(MF3, STAYMORPHED, AActor, flags3),
|
|
|
|
DEFINE_FLAG(MF3, DONTBLAST, AActor, flags3),
|
|
|
|
DEFINE_FLAG(MF3, CANBLAST, AActor, flags3),
|
|
|
|
DEFINE_FLAG(MF3, NOTARGET, AActor, flags3),
|
|
|
|
DEFINE_FLAG(MF3, DONTGIB, AActor, flags3),
|
|
|
|
DEFINE_FLAG(MF3, NOBLOCKMONST, AActor, flags3),
|
|
|
|
DEFINE_FLAG(MF3, FULLVOLDEATH, AActor, flags3),
|
|
|
|
DEFINE_FLAG(MF3, CANBOUNCEWATER, AActor, flags3),
|
|
|
|
DEFINE_FLAG(MF3, NOWALLBOUNCESND, AActor, flags3),
|
|
|
|
DEFINE_FLAG(MF3, FOILINVUL, AActor, flags3),
|
|
|
|
DEFINE_FLAG(MF3, NOTELEOTHER, AActor, flags3),
|
|
|
|
DEFINE_FLAG(MF3, BLOODLESSIMPACT, AActor, flags3),
|
|
|
|
DEFINE_FLAG(MF3, NOEXPLODEFLOOR, AActor, flags3),
|
|
|
|
DEFINE_FLAG(MF3, PUFFONACTORS, AActor, flags3),
|
|
|
|
DEFINE_FLAG(MF4, QUICKTORETALIATE, AActor, flags4),
|
|
|
|
DEFINE_FLAG(MF4, NOICEDEATH, AActor, flags4),
|
|
|
|
DEFINE_FLAG(MF4, RANDOMIZE, AActor, flags4),
|
|
|
|
DEFINE_FLAG(MF4, FIXMAPTHINGPOS , AActor, flags4),
|
|
|
|
DEFINE_FLAG(MF4, ACTLIKEBRIDGE, AActor, flags4),
|
|
|
|
DEFINE_FLAG(MF4, STRIFEDAMAGE, AActor, flags4),
|
|
|
|
DEFINE_FLAG(MF4, LONGMELEERANGE, AActor, flags4),
|
|
|
|
DEFINE_FLAG(MF4, MISSILEMORE, AActor, flags4),
|
|
|
|
DEFINE_FLAG(MF4, MISSILEEVENMORE, AActor, flags4),
|
|
|
|
DEFINE_FLAG(MF4, SHORTMISSILERANGE, AActor, flags4),
|
|
|
|
DEFINE_FLAG(MF4, DONTFALL, AActor, flags4),
|
|
|
|
DEFINE_FLAG(MF4, SEESDAGGERS, AActor, flags4),
|
|
|
|
DEFINE_FLAG(MF4, INCOMBAT, AActor, flags4),
|
|
|
|
DEFINE_FLAG(MF4, LOOKALLAROUND, AActor, flags4),
|
|
|
|
DEFINE_FLAG(MF4, STANDSTILL, AActor, flags4),
|
|
|
|
DEFINE_FLAG(MF4, SPECTRAL, AActor, flags4),
|
|
|
|
DEFINE_FLAG(MF4, FIRERESIST, AActor, flags4),
|
|
|
|
DEFINE_FLAG(MF4, NOSPLASHALERT, AActor, flags4),
|
|
|
|
DEFINE_FLAG(MF4, SYNCHRONIZED, AActor, flags4),
|
|
|
|
DEFINE_FLAG(MF4, NOTARGETSWITCH, AActor, flags4),
|
|
|
|
DEFINE_FLAG(MF4, DONTHURTSPECIES, AActor, flags4),
|
|
|
|
DEFINE_FLAG(MF4, SHIELDREFLECT, AActor, flags4),
|
|
|
|
DEFINE_FLAG(MF4, DEFLECT, AActor, flags4),
|
|
|
|
DEFINE_FLAG(MF4, ALLOWPARTICLES, AActor, flags4),
|
|
|
|
DEFINE_FLAG(MF4, EXTREMEDEATH, AActor, flags4),
|
|
|
|
DEFINE_FLAG(MF4, NOEXTREMEDEATH, AActor, flags4),
|
2006-04-11 16:27:41 +00:00
|
|
|
DEFINE_FLAG(MF4, FRIGHTENED, AActor, flags4),
|
|
|
|
DEFINE_FLAG(MF4, NOBOUNCESOUND, AActor, flags4),
|
2006-07-13 10:17:56 +00:00
|
|
|
DEFINE_FLAG(MF4, NOSKIN, AActor, flags4),
|
2006-11-04 16:19:50 +00:00
|
|
|
DEFINE_FLAG(MF4, BOSSDEATH, AActor, flags4),
|
2006-02-24 04:48:15 +00:00
|
|
|
|
2006-04-17 16:04:27 +00:00
|
|
|
DEFINE_FLAG(MF5, FASTER, AActor, flags5),
|
|
|
|
DEFINE_FLAG(MF5, FASTMELEE, AActor, flags5),
|
|
|
|
DEFINE_FLAG(MF5, NODROPOFF, AActor, flags5),
|
2006-04-18 22:15:05 +00:00
|
|
|
DEFINE_FLAG(MF5, BOUNCEONACTORS, AActor, flags5),
|
|
|
|
DEFINE_FLAG(MF5, EXPLODEONWATER, AActor, flags5),
|
2006-05-07 00:27:22 +00:00
|
|
|
DEFINE_FLAG(MF5, NODAMAGE, AActor, flags5),
|
2006-05-13 12:41:15 +00:00
|
|
|
DEFINE_FLAG(MF5, BLOODSPLATTER, AActor, flags5),
|
2006-07-02 21:58:10 +00:00
|
|
|
DEFINE_FLAG(MF5, OLDRADIUSDMG, AActor, flags5),
|
2006-10-15 20:27:16 +00:00
|
|
|
DEFINE_FLAG(MF5, DEHEXPLOSION, AActor, flags5),
|
2006-10-22 10:32:41 +00:00
|
|
|
DEFINE_FLAG(MF5, PIERCEARMOR, AActor, flags5),
|
2006-04-17 16:04:27 +00:00
|
|
|
|
2006-02-24 04:48:15 +00:00
|
|
|
// Effect flags
|
|
|
|
DEFINE_FLAG(FX, VISIBILITYPULSE, AActor, effects),
|
|
|
|
DEFINE_FLAG2(FX_ROCKET, ROCKETTRAIL, AActor, effects),
|
|
|
|
DEFINE_FLAG2(FX_GRENADE, GRENADETRAIL, AActor, effects),
|
2006-05-03 14:54:48 +00:00
|
|
|
DEFINE_FLAG(RF, INVISIBLE, AActor, renderflags),
|
2006-02-24 04:48:15 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static flagdef InventoryFlags[] =
|
|
|
|
{
|
|
|
|
// Inventory flags
|
|
|
|
DEFINE_FLAG(IF, QUIET, AInventory, ItemFlags),
|
|
|
|
DEFINE_FLAG(IF, AUTOACTIVATE, AInventory, ItemFlags),
|
|
|
|
DEFINE_FLAG(IF, UNDROPPABLE, AInventory, ItemFlags),
|
|
|
|
DEFINE_FLAG(IF, INVBAR, AInventory, ItemFlags),
|
|
|
|
DEFINE_FLAG(IF, HUBPOWER, AInventory, ItemFlags),
|
|
|
|
DEFINE_FLAG(IF, INTERHUBSTRIP, AInventory, ItemFlags),
|
|
|
|
DEFINE_FLAG(IF, PICKUPFLASH, AInventory, ItemFlags),
|
|
|
|
DEFINE_FLAG(IF, ALWAYSPICKUP, AInventory, ItemFlags),
|
|
|
|
DEFINE_FLAG(IF, FANCYPICKUPSOUND, AInventory, ItemFlags),
|
2006-05-03 14:54:48 +00:00
|
|
|
DEFINE_FLAG(IF, BIGPOWERUP, AInventory, ItemFlags),
|
2006-02-24 04:48:15 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static flagdef WeaponFlags[] =
|
|
|
|
{
|
|
|
|
// Weapon flags
|
|
|
|
DEFINE_FLAG(WIF, NOAUTOFIRE, AWeapon, WeaponFlags),
|
|
|
|
DEFINE_FLAG(WIF, READYSNDHALF, AWeapon, WeaponFlags),
|
|
|
|
DEFINE_FLAG(WIF, DONTBOB, AWeapon, WeaponFlags),
|
|
|
|
DEFINE_FLAG(WIF, AXEBLOOD, AWeapon, WeaponFlags),
|
|
|
|
DEFINE_FLAG(WIF, NOALERT, AWeapon, WeaponFlags),
|
|
|
|
DEFINE_FLAG(WIF, AMMO_OPTIONAL, AWeapon, WeaponFlags),
|
|
|
|
DEFINE_FLAG(WIF, ALT_AMMO_OPTIONAL, AWeapon, WeaponFlags),
|
|
|
|
DEFINE_FLAG(WIF, PRIMARY_USES_BOTH, AWeapon, WeaponFlags),
|
|
|
|
DEFINE_FLAG(WIF, WIMPY_WEAPON, AWeapon, WeaponFlags),
|
|
|
|
DEFINE_FLAG(WIF, POWERED_UP, AWeapon, WeaponFlags),
|
|
|
|
//DEFINE_FLAG(WIF, EXTREME_DEATH, AWeapon, WeaponFlags), // this should be removed now!
|
|
|
|
DEFINE_FLAG(WIF, STAFF2_KICKBACK, AWeapon, WeaponFlags),
|
|
|
|
DEFINE_FLAG(WIF_BOT, EXPLOSIVE, AWeapon, WeaponFlags),
|
|
|
|
DEFINE_FLAG2(WIF_BOT_MELEE, MELEEWEAPON, AWeapon, WeaponFlags),
|
|
|
|
DEFINE_FLAG(WIF_BOT, BFG, AWeapon, WeaponFlags),
|
|
|
|
DEFINE_FLAG(WIF, CHEATNOTWEAPON, AWeapon, WeaponFlags),
|
|
|
|
//WIF_BOT_REACTION_SKILL_THING = 1<<31, // I don't understand this
|
|
|
|
};
|
|
|
|
|
2006-05-10 02:40:43 +00:00
|
|
|
static const struct { const PClass *Type; flagdef *Defs; int NumDefs; } FlagLists[] =
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
|
|
|
{ RUNTIME_CLASS(AActor), ActorFlags, sizeof(ActorFlags)/sizeof(flagdef) },
|
|
|
|
{ RUNTIME_CLASS(AInventory), InventoryFlags, sizeof(InventoryFlags)/sizeof(flagdef) },
|
|
|
|
{ RUNTIME_CLASS(AWeapon), WeaponFlags, sizeof(WeaponFlags)/sizeof(flagdef) }
|
|
|
|
};
|
|
|
|
#define NUM_FLAG_LISTS 3
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
// Find a flag by name using a binary search
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
static int STACK_ARGS flagcmp (const void * a, const void * b)
|
|
|
|
{
|
|
|
|
return stricmp( ((flagdef*)a)->name, ((flagdef*)b)->name);
|
|
|
|
}
|
|
|
|
|
|
|
|
static flagdef *FindFlag (flagdef *flags, int numflags, const char *flag)
|
|
|
|
{
|
- Fixed compilation with mingw again.
- Added multiple-choice sound sequences. These overcome one of the major
deficiences of the Hexen-inherited SNDSEQ system while still being Hexen
compatible: Custom door sounds can now use different opening and closing
sequences, for both normal and blazing speeds.
- Added a serializer for TArray.
- Added a countof macro to doomtype.h. See the1's blog to find out why
it's implemented the way it is.
<http://blogs.msdn.com/the1/articles/210011.aspx>
- Added a new method to FRandom for getting random numbers larger than 255,
which lets me:
- Fixed: SNDSEQ delayrand commands could delay for no more than 255 tics.
- Fixed: If you're going to have sector_t.SoundTarget, then they need to
be included in the pointer cleanup scans.
- Ported back newer name code from 2.1.
- Fixed: Using -warp with only one parameter in Doom and Heretic to
select a map on episode 1 no longer worked.
- New: Loading a multiplayer save now restores the players based on
their names rather than on their connection order. Using connection
order was sensible when -net was the only way to start a network game,
but with -host/-join, it's not so nice. Also, if there aren't enough
players in the save, then the extra players will be spawned normally,
so you can continue a saved game with more players than you started it
with.
- Added some new SNDSEQ commands to make it possible to define Heretic's
ambient sounds in SNDSEQ: volumerel, volumerand, slot, randomsequence,
delayonce, and restart. With these, it is basically possible to obsolete
all of the $ambient SNDINFO commands.
- Fixed: Sound sequences would only execute one command each time they were
ticked.
- Fixed: No bounds checking was done on the volume sound sequences played at.
- Fixed: The tic parameter to playloop was useless and caused it to
act like a redundant playrepeat. I have removed all the logic that
caused playloop to play repeating sounds, and now it acts like an
infinite sequence of play/delay commands until the sequence is
stopped.
- Fixed: Sound sequences were ticked every frame, not every tic, so all
the delay commands were timed incorrectly and varied depending on your
framerate. Since this is useful for restarting looping sounds that got
cut off, I have not changed this. Instead, the delay commands now
record the tic when execution should resume, not the number of tics
left to delay.
SVN r57 (trunk)
2006-04-21 01:22:55 +00:00
|
|
|
int min = 0, max = numflags - 1;
|
2006-02-24 04:48:15 +00:00
|
|
|
|
|
|
|
while (min <= max)
|
|
|
|
{
|
|
|
|
int mid = (min + max) / 2;
|
|
|
|
int lexval = stricmp (flag, flags[mid].name);
|
|
|
|
if (lexval == 0)
|
|
|
|
{
|
- Fixed: ActorFlagSetOrReset() wasn't receiving the + or - character from
ParseActorProperties().
- Fixed: The decorate FindFlag() function returned flags from ActorFlags
instead of the passed flags set.
- Fixed: The CHT_CHAINSAW, CHT_POWER, CHT_HEALTH, and CHT_RESSURECT needed
NULL player->mo checks.
- Fixed: The "give all" command didn't give the backpack in Doom, and it
must give the backpack before giving ammo.
- Fixed: P_SetPsprite() must not call the action function if the player is
not attached to an actor. This can happen, for instance, if the level is
destroyed while the player is holding a powered-up Phoenix Rod. As part
of its EndPowerup() function, it sets the psprite to the regular version,
but the player actor has already been destroyed.
- Fixed: FinishThingdef() needs to check for valid names, because weapons
could have inherited valid pointers from their superclass.
- Fixed: fuglyname didn't work.
- Fixed: Redefining $ambient sounds leaked memory.
- Added Jim's crashcatcher.c fix for better shell support.
- VC7.1 seems to have no trouble distinguishing between passing a (const
TypeInfo *) reference to operator<< and the generic, templated (object *)
version, so a few places that can benefit from it now use it. I believe
VC6 had problems with this, which is why I didn't do it all along. The
function's implementation was also moved out of dobject.cpp and into
farchive.cpp.
- Fixed: UnpackPixels() unpacked all chunks in a byte, which is wrong for the
last byte in a row if the image width is not an even multiple of the number
pixels per byte.
- Fixed: P_TranslateLineDef() should only clear monster activation for secret
useable lines, not crossable lines.
- Fixed: Some leftover P_IsHostile() calls still needed to be rewritten.
- Fixed: AWeaponHolder::Serialize() wrote the class type in all circumstances.
SVN r20 (trunk)
2006-03-14 06:11:39 +00:00
|
|
|
return &flags[mid];
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
else if (lexval > 0)
|
|
|
|
{
|
|
|
|
min = mid + 1;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
max = mid - 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2006-05-10 02:40:43 +00:00
|
|
|
static flagdef *FindFlag (const PClass *type, const char *part1, const char *part2)
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
|
|
|
static bool flagsorted = false;
|
|
|
|
flagdef *def;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
if (!flagsorted)
|
|
|
|
{
|
|
|
|
for (i = 0; i < NUM_FLAG_LISTS; ++i)
|
|
|
|
{
|
|
|
|
qsort (FlagLists[i].Defs, FlagLists[i].NumDefs, sizeof(flagdef), flagcmp);
|
|
|
|
}
|
|
|
|
flagsorted = true;
|
|
|
|
}
|
|
|
|
if (part2 == NULL)
|
|
|
|
{ // Search all lists
|
|
|
|
for (i = 0; i < NUM_FLAG_LISTS; ++i)
|
|
|
|
{
|
|
|
|
if (type->IsDescendantOf (FlagLists[i].Type))
|
|
|
|
{
|
|
|
|
def = FindFlag (FlagLists[i].Defs, FlagLists[i].NumDefs, part1);
|
|
|
|
if (def != NULL)
|
|
|
|
{
|
|
|
|
return def;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{ // Search just the named list
|
|
|
|
for (i = 0; i < NUM_FLAG_LISTS; ++i)
|
|
|
|
{
|
2006-05-10 02:40:43 +00:00
|
|
|
if (stricmp (FlagLists[i].Type->TypeName.GetChars(), part1) == 0)
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
|
|
|
if (type->IsDescendantOf (FlagLists[i].Type))
|
|
|
|
{
|
|
|
|
return FindFlag (FlagLists[i].Defs, FlagLists[i].NumDefs, part2);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
//===========================================================================
|
|
|
|
//
|
|
|
|
// A_ChangeFlag
|
|
|
|
//
|
|
|
|
// This cannot be placed in thingdef_codeptr because it needs the flag table
|
|
|
|
//
|
|
|
|
//===========================================================================
|
|
|
|
void A_ChangeFlag(AActor * self)
|
|
|
|
{
|
|
|
|
int index=CheckIndex(2);
|
2006-05-10 15:07:14 +00:00
|
|
|
const char * flagname = FName((ENamedName)StateParameters[index]).GetChars();
|
2006-02-24 04:48:15 +00:00
|
|
|
int expression = EvalExpressionI (StateParameters[index+1], self);
|
|
|
|
|
2006-05-10 15:07:14 +00:00
|
|
|
const char *dot = strchr (flagname, '.');
|
2006-02-24 04:48:15 +00:00
|
|
|
flagdef *fd;
|
|
|
|
|
|
|
|
if (dot != NULL)
|
|
|
|
{
|
2006-05-10 15:07:14 +00:00
|
|
|
FString part1(flagname, dot-flagname);
|
|
|
|
fd = FindFlag (self->GetClass(), part1, dot+1);
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
fd = FindFlag (self->GetClass(), flagname, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (fd != NULL)
|
|
|
|
{
|
|
|
|
int * flagp = (int*) (((char*)self) + fd->structoffset);
|
|
|
|
|
|
|
|
if (expression) *flagp |= fd->flagbit;
|
|
|
|
else *flagp &= ~fd->flagbit;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2006-05-10 02:40:43 +00:00
|
|
|
Printf("Unknown flag '%s' in '%s'\n", flagname, self->GetClass()->TypeName.GetChars());
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
// Action functions
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
|
|
|
|
#include "thingdef_specials.h"
|
|
|
|
|
|
|
|
struct AFuncDesc
|
|
|
|
{
|
2006-12-04 23:25:59 +00:00
|
|
|
const char *Name;
|
2006-02-24 04:48:15 +00:00
|
|
|
actionf_p Function;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// Prototype the code pointers
|
|
|
|
#define WEAPON(x) void A_##x(AActor*);
|
|
|
|
#define ACTOR(x) void A_##x(AActor*);
|
2006-12-04 23:25:59 +00:00
|
|
|
#include "codepointers.h"
|
2006-02-24 04:48:15 +00:00
|
|
|
#include "d_dehackedactions.h"
|
2006-12-04 23:25:59 +00:00
|
|
|
void A_ComboAttack(AActor*);
|
2006-02-24 04:48:15 +00:00
|
|
|
|
2006-12-04 23:25:59 +00:00
|
|
|
AFuncDesc AFTable[] =
|
|
|
|
{
|
|
|
|
#define WEAPON(x) { "A_" #x, A_##x },
|
|
|
|
#define ACTOR(x) { "A_" #x, A_##x },
|
|
|
|
#include "codepointers.h"
|
|
|
|
#include "d_dehackedactions.h"
|
|
|
|
{ "A_Fall", A_NoBlocking },
|
|
|
|
{ "A_BasicAttack", A_ComboAttack }
|
2006-02-24 04:48:15 +00:00
|
|
|
};
|
|
|
|
|
2006-12-04 23:25:59 +00:00
|
|
|
|
2006-02-24 04:48:15 +00:00
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
// Find a function by name using a binary search
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
static int STACK_ARGS funccmp(const void * a, const void * b)
|
|
|
|
{
|
|
|
|
return stricmp( ((AFuncDesc*)a)->Name, ((AFuncDesc*)b)->Name);
|
|
|
|
}
|
|
|
|
|
2006-12-04 23:25:59 +00:00
|
|
|
static AFuncDesc * FindFunction(const char * string)
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
|
|
|
static bool funcsorted=false;
|
|
|
|
|
|
|
|
if (!funcsorted)
|
|
|
|
{
|
- Fixed compilation with mingw again.
- Added multiple-choice sound sequences. These overcome one of the major
deficiences of the Hexen-inherited SNDSEQ system while still being Hexen
compatible: Custom door sounds can now use different opening and closing
sequences, for both normal and blazing speeds.
- Added a serializer for TArray.
- Added a countof macro to doomtype.h. See the1's blog to find out why
it's implemented the way it is.
<http://blogs.msdn.com/the1/articles/210011.aspx>
- Added a new method to FRandom for getting random numbers larger than 255,
which lets me:
- Fixed: SNDSEQ delayrand commands could delay for no more than 255 tics.
- Fixed: If you're going to have sector_t.SoundTarget, then they need to
be included in the pointer cleanup scans.
- Ported back newer name code from 2.1.
- Fixed: Using -warp with only one parameter in Doom and Heretic to
select a map on episode 1 no longer worked.
- New: Loading a multiplayer save now restores the players based on
their names rather than on their connection order. Using connection
order was sensible when -net was the only way to start a network game,
but with -host/-join, it's not so nice. Also, if there aren't enough
players in the save, then the extra players will be spawned normally,
so you can continue a saved game with more players than you started it
with.
- Added some new SNDSEQ commands to make it possible to define Heretic's
ambient sounds in SNDSEQ: volumerel, volumerand, slot, randomsequence,
delayonce, and restart. With these, it is basically possible to obsolete
all of the $ambient SNDINFO commands.
- Fixed: Sound sequences would only execute one command each time they were
ticked.
- Fixed: No bounds checking was done on the volume sound sequences played at.
- Fixed: The tic parameter to playloop was useless and caused it to
act like a redundant playrepeat. I have removed all the logic that
caused playloop to play repeating sounds, and now it acts like an
infinite sequence of play/delay commands until the sequence is
stopped.
- Fixed: Sound sequences were ticked every frame, not every tic, so all
the delay commands were timed incorrectly and varied depending on your
framerate. Since this is useful for restarting looping sounds that got
cut off, I have not changed this. Instead, the delay commands now
record the tic when execution should resume, not the number of tics
left to delay.
SVN r57 (trunk)
2006-04-21 01:22:55 +00:00
|
|
|
qsort(AFTable, countof(AFTable), sizeof(AFTable[0]), funccmp);
|
2006-02-24 04:48:15 +00:00
|
|
|
funcsorted=true;
|
|
|
|
}
|
|
|
|
|
- Fixed compilation with mingw again.
- Added multiple-choice sound sequences. These overcome one of the major
deficiences of the Hexen-inherited SNDSEQ system while still being Hexen
compatible: Custom door sounds can now use different opening and closing
sequences, for both normal and blazing speeds.
- Added a serializer for TArray.
- Added a countof macro to doomtype.h. See the1's blog to find out why
it's implemented the way it is.
<http://blogs.msdn.com/the1/articles/210011.aspx>
- Added a new method to FRandom for getting random numbers larger than 255,
which lets me:
- Fixed: SNDSEQ delayrand commands could delay for no more than 255 tics.
- Fixed: If you're going to have sector_t.SoundTarget, then they need to
be included in the pointer cleanup scans.
- Ported back newer name code from 2.1.
- Fixed: Using -warp with only one parameter in Doom and Heretic to
select a map on episode 1 no longer worked.
- New: Loading a multiplayer save now restores the players based on
their names rather than on their connection order. Using connection
order was sensible when -net was the only way to start a network game,
but with -host/-join, it's not so nice. Also, if there aren't enough
players in the save, then the extra players will be spawned normally,
so you can continue a saved game with more players than you started it
with.
- Added some new SNDSEQ commands to make it possible to define Heretic's
ambient sounds in SNDSEQ: volumerel, volumerand, slot, randomsequence,
delayonce, and restart. With these, it is basically possible to obsolete
all of the $ambient SNDINFO commands.
- Fixed: Sound sequences would only execute one command each time they were
ticked.
- Fixed: No bounds checking was done on the volume sound sequences played at.
- Fixed: The tic parameter to playloop was useless and caused it to
act like a redundant playrepeat. I have removed all the logic that
caused playloop to play repeating sounds, and now it acts like an
infinite sequence of play/delay commands until the sequence is
stopped.
- Fixed: Sound sequences were ticked every frame, not every tic, so all
the delay commands were timed incorrectly and varied depending on your
framerate. Since this is useful for restarting looping sounds that got
cut off, I have not changed this. Instead, the delay commands now
record the tic when execution should resume, not the number of tics
left to delay.
SVN r57 (trunk)
2006-04-21 01:22:55 +00:00
|
|
|
int min = 0, max = countof(AFTable)-1;
|
2006-02-24 04:48:15 +00:00
|
|
|
|
|
|
|
while (min <= max)
|
|
|
|
{
|
|
|
|
int mid = (min + max) / 2;
|
|
|
|
int lexval = stricmp (string, AFTable[mid].Name);
|
|
|
|
if (lexval == 0)
|
|
|
|
{
|
|
|
|
return &AFTable[mid];
|
|
|
|
}
|
|
|
|
else if (lexval > 0)
|
|
|
|
{
|
|
|
|
min = mid + 1;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
max = mid - 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static const char *BasicAttackNames[4] =
|
|
|
|
{
|
|
|
|
"A_MeleeAttack",
|
|
|
|
"A_MissileAttack",
|
|
|
|
"A_ComboAttack",
|
|
|
|
NULL
|
|
|
|
};
|
|
|
|
static const actionf_p BasicAttacks[3] =
|
|
|
|
{
|
|
|
|
A_MeleeAttack,
|
|
|
|
A_MissileAttack,
|
|
|
|
A_ComboAttack
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
//
|
|
|
|
// Translation parsing
|
|
|
|
//
|
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
static int NumUsedTranslations;
|
|
|
|
static int NumUsedBloodTranslations;
|
2006-09-14 00:02:31 +00:00
|
|
|
BYTE decorate_translations[256*256*2];
|
2006-02-24 04:48:15 +00:00
|
|
|
PalEntry BloodTranslations[256];
|
|
|
|
|
|
|
|
void InitDecorateTranslations()
|
|
|
|
{
|
|
|
|
// The translation tables haven't been allocated yet so we may as easily use a static buffer instead!
|
|
|
|
NumUsedBloodTranslations = NumUsedTranslations = 0;
|
|
|
|
for(int i=0;i<256*256*2;i++) decorate_translations[i]=i&255;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool Check(char *& range, char c, bool error=true)
|
|
|
|
{
|
|
|
|
while (isspace(*range)) range++;
|
|
|
|
if (*range==c)
|
|
|
|
{
|
|
|
|
range++;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
if (error)
|
|
|
|
{
|
|
|
|
//SC_ScriptError("Invalid syntax in translation specification: '%c' expected", c);
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void AddToTranslation(unsigned char * translation, char * range)
|
|
|
|
{
|
|
|
|
int start,end;
|
|
|
|
|
|
|
|
start=strtol(range, &range, 10);
|
|
|
|
if (!Check(range, ':')) return;
|
|
|
|
end=strtol(range, &range, 10);
|
|
|
|
if (!Check(range, '=')) return;
|
|
|
|
if (!Check(range, '[', false))
|
|
|
|
{
|
|
|
|
int pal1,pal2;
|
|
|
|
fixed_t palcol, palstep;
|
|
|
|
|
|
|
|
pal1=strtol(range, &range, 10);
|
|
|
|
if (!Check(range, ':')) return;
|
|
|
|
pal2=strtol(range, &range, 10);
|
|
|
|
|
|
|
|
if (start > end)
|
|
|
|
{
|
|
|
|
swap (start, end);
|
|
|
|
swap (pal1, pal2);
|
|
|
|
}
|
|
|
|
else if (start == end)
|
|
|
|
{
|
|
|
|
translation[start] = pal1;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
palcol = pal1 << FRACBITS;
|
|
|
|
palstep = ((pal2 << FRACBITS) - palcol) / (end - start);
|
|
|
|
for (int i = start; i <= end; palcol += palstep, ++i)
|
|
|
|
{
|
|
|
|
translation[i] = palcol >> FRACBITS;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// translation using RGB values
|
|
|
|
int r1;
|
|
|
|
int g1;
|
|
|
|
int b1;
|
|
|
|
int r2;
|
|
|
|
int g2;
|
|
|
|
int b2;
|
|
|
|
int r,g,b;
|
|
|
|
int rs,gs,bs;
|
|
|
|
|
|
|
|
r1=strtol(range, &range, 10);
|
|
|
|
if (!Check(range, ',')) return;
|
|
|
|
g1=strtol(range, &range, 10);
|
|
|
|
if (!Check(range, ',')) return;
|
|
|
|
b1=strtol(range, &range, 10);
|
|
|
|
if (!Check(range, ']')) return;
|
|
|
|
if (!Check(range, ':')) return;
|
|
|
|
if (!Check(range, '[')) return;
|
|
|
|
r2=strtol(range, &range, 10);
|
|
|
|
if (!Check(range, ',')) return;
|
|
|
|
g2=strtol(range, &range, 10);
|
|
|
|
if (!Check(range, ',')) return;
|
|
|
|
b2=strtol(range, &range, 10);
|
|
|
|
if (!Check(range, ']')) return;
|
|
|
|
|
|
|
|
if (start > end)
|
|
|
|
{
|
|
|
|
swap (start, end);
|
|
|
|
r = r2;
|
|
|
|
g = g2;
|
|
|
|
b = b2;
|
|
|
|
rs = r1 - r2;
|
|
|
|
gs = g1 - g2;
|
|
|
|
bs = b1 - b2;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
r = r1;
|
|
|
|
g = g1;
|
|
|
|
b = b1;
|
|
|
|
rs = r2 - r1;
|
|
|
|
gs = g2 - g1;
|
|
|
|
bs = b2 - b1;
|
|
|
|
}
|
|
|
|
if (start == end)
|
|
|
|
{
|
|
|
|
translation[start] = ColorMatcher.Pick
|
|
|
|
(r >> FRACBITS, g >> FRACBITS, b >> FRACBITS);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
rs /= (end - start);
|
|
|
|
gs /= (end - start);
|
|
|
|
bs /= (end - start);
|
|
|
|
for (int i = start; i <= end; ++i)
|
|
|
|
{
|
|
|
|
translation[i] = ColorMatcher.Pick
|
|
|
|
(r >> FRACBITS, g >> FRACBITS, b >> FRACBITS);
|
|
|
|
r += rs;
|
|
|
|
g += gs;
|
|
|
|
b += bs;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static int StoreTranslation(const unsigned char * translation)
|
|
|
|
{
|
|
|
|
for (int i = 0; i < NumUsedTranslations; i++)
|
|
|
|
{
|
|
|
|
if (!memcmp(translation, decorate_translations + i*256, 256))
|
|
|
|
{
|
|
|
|
// A duplicate of this translation already exists
|
|
|
|
return TRANSLATION(TRANSLATION_Decorate, i);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (NumUsedTranslations>=MAX_DECORATE_TRANSLATIONS)
|
|
|
|
{
|
|
|
|
SC_ScriptError("Too many translations in DECORATE");
|
|
|
|
}
|
|
|
|
memcpy(decorate_translations + NumUsedTranslations*256, translation, 256);
|
|
|
|
NumUsedTranslations++;
|
|
|
|
return TRANSLATION(TRANSLATION_Decorate, NumUsedTranslations-1);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int CreateBloodTranslation(PalEntry color)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < NumUsedBloodTranslations; i++)
|
|
|
|
{
|
|
|
|
if (color.r == BloodTranslations[i].r &&
|
|
|
|
color.g == BloodTranslations[i].g &&
|
|
|
|
color.b == BloodTranslations[i].b)
|
|
|
|
{
|
|
|
|
// A duplicate of this translation already exists
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (NumUsedBloodTranslations>=MAX_DECORATE_TRANSLATIONS)
|
|
|
|
{
|
|
|
|
SC_ScriptError("Too many blood colors in DECORATE");
|
|
|
|
}
|
|
|
|
for (i = 0; i < 256; i++)
|
|
|
|
{
|
|
|
|
int bright = MAX(MAX(GPalette.BaseColors[i].r, GPalette.BaseColors[i].g), GPalette.BaseColors[i].b);
|
|
|
|
int entry = ColorMatcher.Pick(color.r*bright/255, color.g*bright/255, color.b*bright/255);
|
|
|
|
|
|
|
|
*(decorate_translations + MAX_DECORATE_TRANSLATIONS*256 + NumUsedBloodTranslations*256 + i)=entry;
|
|
|
|
}
|
|
|
|
BloodTranslations[NumUsedBloodTranslations]=color;
|
|
|
|
return NumUsedBloodTranslations++;
|
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
//
|
|
|
|
// DropItem handling
|
|
|
|
//
|
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
|
2006-05-09 03:40:15 +00:00
|
|
|
static void FreeDropItemChain(FDropItem *chain)
|
|
|
|
{
|
|
|
|
while (chain != NULL)
|
|
|
|
{
|
|
|
|
FDropItem *next = chain->Next;
|
|
|
|
delete chain;
|
|
|
|
chain = next;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
class FDropItemPtrArray : public TArray<FDropItem *>
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
~FDropItemPtrArray()
|
|
|
|
{
|
|
|
|
for (unsigned int i = 0; i < Size(); ++i)
|
|
|
|
{
|
|
|
|
FreeDropItemChain ((*this)[i]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2006-07-13 10:17:56 +00:00
|
|
|
static FDropItemPtrArray DropItemList;
|
2006-02-24 04:48:15 +00:00
|
|
|
|
2006-11-05 21:46:28 +00:00
|
|
|
FDropItem *GetDropItems(const PClass *cls)
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
2006-11-05 21:46:28 +00:00
|
|
|
unsigned int index = cls->Meta.GetMetaInt (ACMETA_DropItems) - 1;
|
2006-02-24 04:48:15 +00:00
|
|
|
|
|
|
|
if (index >= 0 && index < DropItemList.Size())
|
|
|
|
{
|
2006-07-13 10:17:56 +00:00
|
|
|
return DropItemList[index];
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
2006-07-13 10:17:56 +00:00
|
|
|
return NULL;
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
// Extra info maintained while defining an actor. The original
|
|
|
|
// implementation stored these in a CustomActor class. They have all been
|
|
|
|
// moved into action function parameters so that no special CustomActor
|
|
|
|
// class is necessary.
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
struct FBasicAttack
|
|
|
|
{
|
|
|
|
int MeleeDamage;
|
|
|
|
int MeleeSound;
|
2006-05-09 03:40:15 +00:00
|
|
|
FName MissileName;
|
2006-02-24 04:48:15 +00:00
|
|
|
fixed_t MissileHeight;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct Baggage
|
|
|
|
{
|
|
|
|
FActorInfo *Info;
|
|
|
|
bool DropItemSet;
|
|
|
|
bool StateSet;
|
|
|
|
int CurrentState;
|
|
|
|
|
|
|
|
FDropItem *DropItemList;
|
|
|
|
FBasicAttack BAttack;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
static TArray<FState> StateArray;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
typedef void (*ActorPropFunction) (AActor *defaults, Baggage &bag);
|
|
|
|
|
2006-05-10 02:40:43 +00:00
|
|
|
struct ActorProps { const char *name; ActorPropFunction Handler; const PClass * type; };
|
2006-02-24 04:48:15 +00:00
|
|
|
|
|
|
|
typedef ActorProps (*ActorPropHandler) (register const char *str, register unsigned int len);
|
|
|
|
|
|
|
|
static const ActorProps *is_actorprop (const char *str);
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
// Find a state address
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
2006-10-31 14:53:21 +00:00
|
|
|
struct FStateDefine
|
|
|
|
{
|
|
|
|
FName Label;
|
|
|
|
TArray<FStateDefine> Children;
|
|
|
|
FState *State;
|
|
|
|
};
|
2006-02-24 04:48:15 +00:00
|
|
|
|
2006-10-31 14:53:21 +00:00
|
|
|
static TArray<FStateDefine> StateLabels;
|
2006-02-24 04:48:15 +00:00
|
|
|
|
2006-10-31 14:53:21 +00:00
|
|
|
void ClearStateLabels()
|
|
|
|
{
|
|
|
|
StateLabels.Clear();
|
|
|
|
}
|
2006-02-24 04:48:15 +00:00
|
|
|
|
2006-10-31 14:53:21 +00:00
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
// Search one list of state definitions for the given name
|
|
|
|
//
|
|
|
|
//==========================================================================
|
2006-02-24 04:48:15 +00:00
|
|
|
|
2006-10-31 14:53:21 +00:00
|
|
|
static FStateDefine * FindStateLabelInList(TArray<FStateDefine> & list, FName name, bool create)
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
2006-10-31 14:53:21 +00:00
|
|
|
for(unsigned i = 0; i<list.Size(); i++)
|
|
|
|
{
|
|
|
|
if (list[i].Label == name) return &list[i];
|
|
|
|
}
|
|
|
|
if (create)
|
|
|
|
{
|
|
|
|
FStateDefine def;
|
|
|
|
def.Label=name;
|
|
|
|
def.State=NULL;
|
|
|
|
return &list[list.Push(def)];
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
// Creates a list of names from a string. Dots are used as separator
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
void MakeStateNameList(const char * fname, TArray<FName> * out)
|
|
|
|
{
|
|
|
|
FName firstpart, secondpart;
|
|
|
|
char * c;
|
2006-02-24 04:48:15 +00:00
|
|
|
|
2006-10-31 14:53:21 +00:00
|
|
|
// Handle the old names for the existing death states
|
|
|
|
char * name = copystring(fname);
|
|
|
|
firstpart = strtok(name, ".");
|
|
|
|
switch (firstpart)
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
2006-10-31 14:53:21 +00:00
|
|
|
case NAME_Burn:
|
|
|
|
firstpart = NAME_Death;
|
|
|
|
secondpart = NAME_Fire;
|
|
|
|
break;
|
|
|
|
case NAME_Ice:
|
|
|
|
firstpart = NAME_Death;
|
|
|
|
secondpart = NAME_Ice;
|
|
|
|
break;
|
|
|
|
case NAME_Disintegrate:
|
|
|
|
firstpart = NAME_Death;
|
|
|
|
secondpart = NAME_Disintegrate;
|
|
|
|
break;
|
|
|
|
case NAME_XDeath:
|
|
|
|
firstpart = NAME_Death;
|
|
|
|
secondpart = NAME_Extreme;
|
|
|
|
break;
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
2006-10-31 14:53:21 +00:00
|
|
|
|
|
|
|
out->Clear();
|
|
|
|
out->Push(firstpart);
|
|
|
|
if (secondpart!=NAME_None) out->Push(secondpart);
|
|
|
|
|
|
|
|
while ((c = strtok(NULL, "."))!=NULL)
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
2006-10-31 14:53:21 +00:00
|
|
|
FName cc = c;
|
|
|
|
out->Push(cc);
|
|
|
|
}
|
|
|
|
delete [] name;
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
// Finds the address of a state given by name.
|
|
|
|
// Adds the state if it doesn't exist
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
static FStateDefine * FindStateAddress(const char * name)
|
|
|
|
{
|
|
|
|
static TArray<FName> namelist(3);
|
|
|
|
FStateDefine * statedef=NULL;
|
|
|
|
|
|
|
|
MakeStateNameList(name, &namelist);
|
|
|
|
|
|
|
|
TArray<FStateDefine> * statelist = &StateLabels;
|
|
|
|
for(unsigned i=0;i<namelist.Size();i++)
|
|
|
|
{
|
|
|
|
statedef = FindStateLabelInList(*statelist, namelist[i], true);
|
|
|
|
statelist = &statedef->Children;
|
|
|
|
}
|
|
|
|
return statedef;
|
|
|
|
}
|
|
|
|
|
|
|
|
void AddState (const char * statename, FState * state)
|
|
|
|
{
|
|
|
|
FStateDefine * std = FindStateAddress(statename);
|
|
|
|
std->State = state;
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
// Finds the state associated with the given name
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
FState * FindState(AActor * actor, const PClass * type, const char * name)
|
|
|
|
{
|
|
|
|
static TArray<FName> namelist(3);
|
|
|
|
FStateDefine * statedef=NULL;
|
|
|
|
|
|
|
|
MakeStateNameList(name, &namelist);
|
|
|
|
|
|
|
|
TArray<FStateDefine> * statelist = &StateLabels;
|
|
|
|
for(unsigned i=0;i<namelist.Size();i++)
|
|
|
|
{
|
|
|
|
statedef = FindStateLabelInList(*statelist, namelist[i], false);
|
2006-12-16 12:50:36 +00:00
|
|
|
if (statedef == NULL) return NULL;
|
2006-10-31 14:53:21 +00:00
|
|
|
statelist = &statedef->Children;
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
2006-10-31 14:53:21 +00:00
|
|
|
return statedef? statedef->State : NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
// Finds the state associated with the given name
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
FState * FindStateInClass(AActor * actor, const PClass * type, const char * name)
|
|
|
|
{
|
|
|
|
static TArray<FName> namelist(3);
|
|
|
|
|
|
|
|
MakeStateNameList(name, &namelist);
|
|
|
|
FActorInfo * info = type->ActorInfo;
|
|
|
|
if (info) return info->FindStateExact(namelist.Size(), (va_list)&namelist[0]);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
// Checks if a state list is empty
|
|
|
|
// A list is empty if it doesn't contain any states and no children
|
|
|
|
// that contain any states
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
static bool IsStateListEmpty(TArray<FStateDefine> & statelist)
|
|
|
|
{
|
|
|
|
for(unsigned i=0;i<statelist.Size();i++)
|
|
|
|
{
|
|
|
|
if (statelist[i].State!=NULL || !IsStateListEmpty(statelist[i].Children)) return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
// Creates the final list of states from the state definitions
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
static int STACK_ARGS labelcmp(const void * a, const void * b)
|
|
|
|
{
|
|
|
|
FStateLabel * A = (FStateLabel *)a;
|
|
|
|
FStateLabel * B = (FStateLabel *)b;
|
|
|
|
return ((int)A->Label - (int)B->Label);
|
|
|
|
}
|
|
|
|
|
|
|
|
static FStateLabels * CreateStateLabelList(TArray<FStateDefine> & statelist)
|
|
|
|
{
|
2006-12-16 12:50:36 +00:00
|
|
|
// First delete all empty labels from the list
|
|
|
|
for (int i=statelist.Size()-1;i>=0;i--)
|
|
|
|
{
|
|
|
|
if (statelist[i].Label == NAME_None || (statelist[i].State == NULL && statelist[i].Children.Size() == 0))
|
|
|
|
{
|
|
|
|
statelist.Delete(i);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-10-31 14:53:21 +00:00
|
|
|
int count=statelist.Size();
|
|
|
|
|
|
|
|
if (count == 0) return NULL;
|
|
|
|
|
|
|
|
FStateLabels * list = (FStateLabels*)M_Malloc(sizeof(FStateLabels)+(count-1)*sizeof(FStateLabel));
|
|
|
|
list->NumLabels = count;
|
|
|
|
|
2006-12-16 12:50:36 +00:00
|
|
|
for (int i=0;i<count;i++)
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
2006-12-16 12:50:36 +00:00
|
|
|
list->Labels[i].Label = statelist[i].Label;
|
|
|
|
list->Labels[i].State = statelist[i].State;
|
|
|
|
list->Labels[i].Children = CreateStateLabelList(statelist[i].Children);
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
2006-10-31 14:53:21 +00:00
|
|
|
qsort(list->Labels, count, sizeof(FStateLabel), labelcmp);
|
|
|
|
return list;
|
|
|
|
}
|
|
|
|
|
|
|
|
//===========================================================================
|
|
|
|
//
|
|
|
|
// InstallStates
|
|
|
|
//
|
|
|
|
// Creates the actor's state list from the current definition
|
|
|
|
//
|
|
|
|
//===========================================================================
|
|
|
|
|
|
|
|
void InstallStates(FActorInfo *info, AActor *defaults)
|
|
|
|
{
|
2006-12-16 12:50:36 +00:00
|
|
|
// First ensure we have a valid spawn state.
|
2006-10-31 14:53:21 +00:00
|
|
|
FState * state = FindState(defaults, info->Class, "Spawn");
|
2006-12-16 12:50:36 +00:00
|
|
|
|
|
|
|
// Stateless actors that are direct subclasses of AActor
|
|
|
|
// have their spawnstate default to something that won't
|
|
|
|
// immediately destroy them.
|
|
|
|
if (state == &AActor::States[2] && info->Class->ParentClass == RUNTIME_CLASS(AActor))
|
2006-03-12 22:04:49 +00:00
|
|
|
{
|
2006-10-31 14:53:21 +00:00
|
|
|
AddState("Spawn", &AActor::States[0]);
|
|
|
|
}
|
2006-12-16 12:50:36 +00:00
|
|
|
else if (state == NULL)
|
|
|
|
{
|
|
|
|
// A NULL spawn state will crash the engine so set it to something that will make
|
|
|
|
// the actor disappear as quickly as possible.
|
|
|
|
AddState("Spawn", &AActor::States[2]);
|
|
|
|
}
|
2006-10-31 14:53:21 +00:00
|
|
|
|
2006-12-16 12:50:36 +00:00
|
|
|
if (info->StateList != NULL)
|
|
|
|
{
|
|
|
|
info->StateList->Destroy();
|
|
|
|
free(info->StateList);
|
|
|
|
}
|
2006-10-31 14:53:21 +00:00
|
|
|
info->StateList = CreateStateLabelList(StateLabels);
|
|
|
|
|
|
|
|
// Cache these states as member veriables.
|
|
|
|
defaults->SpawnState = info->FindStateExact(1,NAME_Spawn);
|
|
|
|
defaults->SeeState = info->FindStateExact(1,NAME_See);
|
|
|
|
// Melee and Missile states are manipulated by the scripted marines so they
|
|
|
|
// have to be stored locally
|
|
|
|
defaults->MeleeState = info->FindStateExact(1,NAME_Melee);
|
|
|
|
defaults->MissileState = info->FindStateExact(1,NAME_Missile);
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2006-10-31 14:53:21 +00:00
|
|
|
//===========================================================================
|
|
|
|
//
|
|
|
|
// MakeStateDefines
|
|
|
|
//
|
|
|
|
// Creates a list of state definitions from an existing actor
|
|
|
|
// Used by Dehacked to modify an actor's state list
|
|
|
|
//
|
|
|
|
//===========================================================================
|
|
|
|
|
|
|
|
static void MakeStateList(const FStateLabels *list, TArray<FStateDefine> &dest)
|
|
|
|
{
|
|
|
|
dest.Clear();
|
2006-11-14 16:54:02 +00:00
|
|
|
if (list != NULL) for(int i=0;i<list->NumLabels;i++)
|
2006-10-31 14:53:21 +00:00
|
|
|
{
|
|
|
|
FStateDefine def;
|
|
|
|
|
|
|
|
def.Label = list->Labels[i].Label;
|
|
|
|
def.State = list->Labels[i].State;
|
|
|
|
dest.Push(def);
|
|
|
|
if (list->Labels[i].Children != NULL)
|
|
|
|
{
|
|
|
|
MakeStateList(list->Labels[i].Children, dest[dest.Size()-1].Children);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void MakeStateDefines(const FStateLabels *list)
|
|
|
|
{
|
|
|
|
MakeStateList(list, StateLabels);
|
|
|
|
}
|
|
|
|
|
2006-02-24 04:48:15 +00:00
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
// Sets the default values with which an actor definition starts
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
static void ResetBaggage (Baggage *bag)
|
|
|
|
{
|
|
|
|
bag->DropItemList = NULL;
|
2006-07-26 09:50:17 +00:00
|
|
|
bag->BAttack.MeleeDamage = 0;
|
2006-02-24 04:48:15 +00:00
|
|
|
bag->BAttack.MissileHeight = 32*FRACUNIT;
|
|
|
|
bag->BAttack.MeleeSound = 0;
|
2006-05-09 03:40:15 +00:00
|
|
|
bag->BAttack.MissileName = NAME_None;
|
2006-02-24 04:48:15 +00:00
|
|
|
bag->DropItemSet = false;
|
|
|
|
bag->CurrentState = 0;
|
|
|
|
bag->StateSet = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void ResetActor (AActor *actor, Baggage *bag)
|
|
|
|
{
|
|
|
|
memcpy (actor, GetDefault<AActor>(), sizeof(AActor));
|
2006-05-09 03:40:15 +00:00
|
|
|
if (bag->DropItemList != NULL)
|
|
|
|
{
|
|
|
|
FreeDropItemChain (bag->DropItemList);
|
|
|
|
}
|
2006-02-24 04:48:15 +00:00
|
|
|
ResetBaggage (bag);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
// Starts a new actor definition
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
static FActorInfo * CreateNewActor(FActorInfo ** parentc, Baggage *bag)
|
|
|
|
{
|
2006-05-10 02:40:43 +00:00
|
|
|
FName typeName;
|
2006-02-24 04:48:15 +00:00
|
|
|
|
2006-07-08 02:17:35 +00:00
|
|
|
// Get actor name
|
2006-02-24 04:48:15 +00:00
|
|
|
SC_MustGetString();
|
2006-07-03 09:07:56 +00:00
|
|
|
|
|
|
|
char * colon = strchr(sc_String, ':');
|
|
|
|
if (colon != NULL)
|
|
|
|
{
|
|
|
|
*colon++ = 0;
|
|
|
|
}
|
2006-02-24 04:48:15 +00:00
|
|
|
|
2006-05-10 02:40:43 +00:00
|
|
|
if (PClass::FindClass (sc_String) != NULL)
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
|
|
|
SC_ScriptError ("Actor %s is already defined.", sc_String);
|
|
|
|
}
|
|
|
|
|
2006-05-10 02:40:43 +00:00
|
|
|
typeName = sc_String;
|
2006-02-24 04:48:15 +00:00
|
|
|
|
2006-05-10 02:40:43 +00:00
|
|
|
PClass * parent = RUNTIME_CLASS(AActor);
|
2006-02-24 04:48:15 +00:00
|
|
|
if (parentc)
|
|
|
|
{
|
|
|
|
*parentc = NULL;
|
2006-07-03 09:07:56 +00:00
|
|
|
|
|
|
|
// Do some tweaking so that a definition like 'Actor:Parent' which is read as a single token is recognized as well
|
|
|
|
// without having resort to C-mode (which disallows periods in actor names.)
|
|
|
|
if (colon == NULL)
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
2006-07-03 09:07:56 +00:00
|
|
|
SC_MustGetString ();
|
|
|
|
if (sc_String[0]==':')
|
|
|
|
{
|
|
|
|
colon = sc_String + 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (colon != NULL)
|
|
|
|
{
|
|
|
|
if (colon[0] == 0)
|
|
|
|
{
|
|
|
|
SC_MustGetString ();
|
|
|
|
colon = sc_String;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (colon != NULL)
|
|
|
|
{
|
|
|
|
parent = const_cast<PClass *> (PClass::FindClass (colon));
|
2006-02-24 04:48:15 +00:00
|
|
|
|
|
|
|
if (parent == NULL)
|
|
|
|
{
|
2006-07-03 09:07:56 +00:00
|
|
|
SC_ScriptError ("Parent type '%s' not found", colon);
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
else if (parent->ActorInfo == NULL)
|
|
|
|
{
|
2006-07-03 09:07:56 +00:00
|
|
|
SC_ScriptError ("Parent type '%s' is not an actor", colon);
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
*parentc = parent->ActorInfo;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else SC_UnGet();
|
|
|
|
}
|
|
|
|
|
2006-05-10 02:40:43 +00:00
|
|
|
PClass * ti = parent->CreateDerivedClass (typeName, parent->Size);
|
2006-02-24 04:48:15 +00:00
|
|
|
FActorInfo * info = ti->ActorInfo;
|
|
|
|
|
|
|
|
Decorations.Push (info);
|
2006-12-16 12:50:36 +00:00
|
|
|
MakeStateDefines(parent->ActorInfo->StateList);
|
2006-07-08 02:17:35 +00:00
|
|
|
info->NumOwnedStates = 0;
|
|
|
|
info->OwnedStates = NULL;
|
|
|
|
info->SpawnID = 0;
|
2006-10-31 14:53:21 +00:00
|
|
|
info->StateList = NULL;
|
2006-02-24 04:48:15 +00:00
|
|
|
|
|
|
|
ResetBaggage (bag);
|
|
|
|
bag->Info = info;
|
|
|
|
|
2006-07-08 02:17:35 +00:00
|
|
|
info->DoomEdNum = -1;
|
|
|
|
|
|
|
|
// Check for "replaces"
|
|
|
|
SC_MustGetString ();
|
|
|
|
if (SC_Compare ("replaces"))
|
|
|
|
{
|
|
|
|
const PClass *replacee;
|
|
|
|
|
|
|
|
// Get actor name
|
|
|
|
SC_MustGetString ();
|
|
|
|
replacee = PClass::FindClass (sc_String);
|
|
|
|
|
|
|
|
if (replacee == NULL)
|
|
|
|
{
|
|
|
|
SC_ScriptError ("Replaced type '%s' not found", sc_String);
|
|
|
|
}
|
|
|
|
else if (replacee->ActorInfo == NULL)
|
|
|
|
{
|
|
|
|
SC_ScriptError ("Replaced type '%s' is not an actor", sc_String);
|
|
|
|
}
|
|
|
|
replacee->ActorInfo->Replacement = ti->ActorInfo;
|
2006-07-16 15:00:10 +00:00
|
|
|
ti->ActorInfo->Replacee = replacee->ActorInfo;
|
2006-07-08 02:17:35 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
SC_UnGet();
|
|
|
|
}
|
2006-07-03 09:07:56 +00:00
|
|
|
|
|
|
|
// Now, after the actor names have been parsed, it is time to switch to C-mode
|
|
|
|
// for the rest of the actor definition.
|
|
|
|
SC_SetCMode (true);
|
2006-02-24 04:48:15 +00:00
|
|
|
if (SC_CheckNumber())
|
|
|
|
{
|
2006-07-03 09:07:56 +00:00
|
|
|
if (sc_Number>=-1 && sc_Number<32768) info->DoomEdNum = sc_Number;
|
2006-02-24 04:48:15 +00:00
|
|
|
else SC_ScriptError ("DoomEdNum must be in the range [-1,32767]");
|
|
|
|
}
|
2006-07-03 09:07:56 +00:00
|
|
|
if (parent == RUNTIME_CLASS(AWeapon))
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
|
|
|
// preinitialize kickback to the default for the game
|
2006-05-10 02:40:43 +00:00
|
|
|
((AWeapon*)(info->Class->Defaults))->Kickback=gameinfo.defKickback;
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return info;
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
// PrepareStateParameters
|
|
|
|
// creates an empty parameter list for a parameterized function call
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
int PrepareStateParameters(FState * state, int numparams)
|
|
|
|
{
|
|
|
|
int paramindex=StateParameters.Size();
|
|
|
|
int i, v;
|
|
|
|
|
|
|
|
v=0;
|
|
|
|
for(i=0;i<numparams;i++) StateParameters.Push(v);
|
2006-10-29 11:01:00 +00:00
|
|
|
state->ParameterIndex = paramindex+1;
|
|
|
|
return paramindex;
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
// Returns the index of the given line special
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
int FindLineSpecial(const char * string)
|
|
|
|
{
|
|
|
|
const ACSspecials *spec;
|
|
|
|
|
|
|
|
spec = is_special(string, (unsigned int)strlen(string));
|
|
|
|
if (spec) return spec->Special;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2006-08-16 20:56:06 +00:00
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
// FindLineSpecialEx
|
|
|
|
//
|
|
|
|
// Like FindLineSpecial, but also returns the min and max argument count.
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
int FindLineSpecialEx (const char *string, int *min_args, int *max_args)
|
|
|
|
{
|
|
|
|
const ACSspecials *spec;
|
|
|
|
|
|
|
|
spec = is_special(string, (unsigned int)strlen(string));
|
|
|
|
if (spec != NULL)
|
|
|
|
{
|
|
|
|
*min_args = spec->MinArgs;
|
|
|
|
*max_args = MAX(spec->MinArgs, spec->MaxArgs);
|
|
|
|
return spec->Special;
|
|
|
|
}
|
|
|
|
*min_args = *max_args = 0;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2006-02-24 04:48:15 +00:00
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
// DoSpecialFunctions
|
|
|
|
// handles special functions that can't be dealt with by the generic routine
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
bool DoSpecialFunctions(FState & state, bool multistate, int * statecount, Baggage &bag)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
const ACSspecials *spec;
|
|
|
|
|
|
|
|
if ((spec = is_special (sc_String, sc_StringLen)) != NULL)
|
|
|
|
{
|
|
|
|
|
|
|
|
int paramindex=PrepareStateParameters(&state, 6);
|
|
|
|
|
|
|
|
StateParameters[paramindex]=spec->Special;
|
|
|
|
|
|
|
|
// Make this consistent with all other parameter parsing
|
|
|
|
if (SC_CheckString("("))
|
|
|
|
{
|
|
|
|
for (i = 0; i < 5;)
|
|
|
|
{
|
2006-11-29 04:51:16 +00:00
|
|
|
StateParameters[paramindex+i+1]=ParseExpression (false, bag.Info->Class);
|
2006-02-24 04:48:15 +00:00
|
|
|
i++;
|
2006-11-26 12:13:12 +00:00
|
|
|
if (!SC_CheckString (",")) break;
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
SC_MustGetStringName (")");
|
|
|
|
}
|
|
|
|
else i=0;
|
|
|
|
|
|
|
|
if (i < spec->MinArgs)
|
|
|
|
{
|
|
|
|
SC_ScriptError ("Too few arguments to %s", spec->name);
|
|
|
|
}
|
|
|
|
if (i > MAX (spec->MinArgs, spec->MaxArgs))
|
|
|
|
{
|
|
|
|
SC_ScriptError ("Too many arguments to %s", spec->name);
|
|
|
|
}
|
|
|
|
state.Action = A_CallSpecial;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check for A_MeleeAttack, A_MissileAttack, or A_ComboAttack
|
|
|
|
int batk = SC_MatchString (BasicAttackNames);
|
|
|
|
if (batk >= 0)
|
|
|
|
{
|
|
|
|
int paramindex=PrepareStateParameters(&state, 4);
|
|
|
|
|
|
|
|
StateParameters[paramindex] = bag.BAttack.MeleeDamage;
|
|
|
|
StateParameters[paramindex+1] = bag.BAttack.MeleeSound;
|
2006-05-09 03:40:15 +00:00
|
|
|
StateParameters[paramindex+2] = bag.BAttack.MissileName;
|
2006-02-24 04:48:15 +00:00
|
|
|
StateParameters[paramindex+3] = bag.BAttack.MissileHeight;
|
|
|
|
state.Action = BasicAttacks[batk];
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
// RetargetState(Pointer)s
|
|
|
|
//
|
|
|
|
// These functions are used when a goto follows one or more labels.
|
|
|
|
// Because multiple labels are permitted to occur consecutively with no
|
|
|
|
// intervening states, it is not enough to remember the last label defined
|
|
|
|
// and adjust it. So these functions search for all labels that point to
|
|
|
|
// the current position in the state array and give them a copy of the
|
|
|
|
// target string instead.
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
2006-10-31 14:53:21 +00:00
|
|
|
static void RetargetStatePointers (intptr_t count, const char *target, TArray<FStateDefine> & statelist)
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
2006-10-31 14:53:21 +00:00
|
|
|
for(unsigned i = 0;i<statelist.Size(); i++)
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
2006-10-31 14:53:21 +00:00
|
|
|
if (statelist[i].State == (FState*)count)
|
|
|
|
{
|
|
|
|
statelist[i].State = target == NULL ? NULL : (FState *)copystring (target);
|
|
|
|
}
|
|
|
|
if (statelist[i].Children.Size() > 0)
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
2006-10-31 14:53:21 +00:00
|
|
|
RetargetStatePointers(count, target, statelist[i].Children);
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-10-31 14:53:21 +00:00
|
|
|
static void RetargetStates (intptr_t count, const char *target)
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
2006-10-31 14:53:21 +00:00
|
|
|
RetargetStatePointers(count, target, StateLabels);
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
2006-10-29 11:01:00 +00:00
|
|
|
// Reads a state label that may contain '.'s.
|
2006-02-24 04:48:15 +00:00
|
|
|
// processes a state block
|
|
|
|
//
|
|
|
|
//==========================================================================
|
2006-11-04 22:26:04 +00:00
|
|
|
static FString ParseStateString()
|
2006-10-29 11:01:00 +00:00
|
|
|
{
|
2006-11-04 22:26:04 +00:00
|
|
|
FString statestring;
|
|
|
|
|
2006-10-29 11:01:00 +00:00
|
|
|
SC_MustGetString();
|
2006-11-04 22:26:04 +00:00
|
|
|
statestring = sc_String;
|
|
|
|
if (SC_CheckString("::"))
|
|
|
|
{
|
|
|
|
SC_MustGetString ();
|
|
|
|
statestring += "::";
|
|
|
|
statestring += sc_String;
|
|
|
|
}
|
2006-10-29 11:01:00 +00:00
|
|
|
while (SC_CheckString ("."))
|
|
|
|
{
|
|
|
|
SC_MustGetString ();
|
2006-11-04 22:26:04 +00:00
|
|
|
statestring += ".";
|
|
|
|
statestring += sc_String;
|
2006-10-29 11:01:00 +00:00
|
|
|
}
|
2006-11-04 22:26:04 +00:00
|
|
|
return statestring;
|
2006-10-29 11:01:00 +00:00
|
|
|
}
|
2006-02-24 04:48:15 +00:00
|
|
|
|
2006-10-29 11:01:00 +00:00
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
// ProcessStates
|
|
|
|
// processes a state block
|
|
|
|
//
|
|
|
|
//==========================================================================
|
2006-02-24 04:48:15 +00:00
|
|
|
static int ProcessStates(FActorInfo * actor, AActor * defaults, Baggage &bag)
|
|
|
|
{
|
2006-11-04 22:26:04 +00:00
|
|
|
FString statestring;
|
2006-02-24 04:48:15 +00:00
|
|
|
intptr_t count = 0;
|
|
|
|
FState state;
|
|
|
|
FState * laststate = NULL;
|
|
|
|
intptr_t lastlabel = -1;
|
2006-05-06 03:25:12 +00:00
|
|
|
int minrequiredstate = -1;
|
2006-02-24 04:48:15 +00:00
|
|
|
|
2006-11-26 12:13:12 +00:00
|
|
|
SC_MustGetStringName ("{");
|
2006-10-29 11:01:00 +00:00
|
|
|
SC_SetEscape(false); // disable escape sequences in the state parser
|
2006-11-26 12:13:12 +00:00
|
|
|
while (!SC_CheckString ("}") && !sc_End)
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
|
|
|
memset(&state,0,sizeof(state));
|
2006-11-04 22:26:04 +00:00
|
|
|
statestring = ParseStateString();
|
|
|
|
if (!statestring.CompareNoCase("GOTO"))
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
2006-10-29 11:01:00 +00:00
|
|
|
do_goto:
|
2006-11-04 22:26:04 +00:00
|
|
|
statestring = ParseStateString();
|
2006-02-24 04:48:15 +00:00
|
|
|
if (SC_CheckString ("+"))
|
|
|
|
{
|
|
|
|
SC_MustGetNumber ();
|
2006-11-04 22:26:04 +00:00
|
|
|
statestring += '+';
|
|
|
|
statestring += sc_String;
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
// copy the text - this must be resolved later!
|
|
|
|
if (laststate != NULL)
|
|
|
|
{ // Following a state definition: Modify it.
|
2006-05-09 03:40:15 +00:00
|
|
|
laststate->NextState = (FState*)copystring(statestring);
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
else if (lastlabel >= 0)
|
|
|
|
{ // Following a label: Retarget it.
|
2006-10-31 14:53:21 +00:00
|
|
|
RetargetStates (count+1, statestring);
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
SC_ScriptError("GOTO before first state");
|
|
|
|
}
|
|
|
|
}
|
2006-11-04 22:26:04 +00:00
|
|
|
else if (!statestring.CompareNoCase("STOP"))
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
2006-05-07 23:55:17 +00:00
|
|
|
do_stop:
|
|
|
|
if (laststate!=NULL)
|
|
|
|
{
|
|
|
|
laststate->NextState=(FState*)-1;
|
|
|
|
}
|
|
|
|
else if (lastlabel >=0)
|
|
|
|
{
|
2006-10-31 14:53:21 +00:00
|
|
|
RetargetStates (count+1, NULL);
|
2006-05-07 23:55:17 +00:00
|
|
|
}
|
|
|
|
else
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
|
|
|
SC_ScriptError("STOP before first state");
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
2006-11-04 22:26:04 +00:00
|
|
|
else if (!statestring.CompareNoCase("WAIT") || !statestring.CompareNoCase("FAIL"))
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
|
|
|
if (!laststate)
|
|
|
|
{
|
|
|
|
SC_ScriptError("%s before first state", sc_String);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
laststate->NextState=(FState*)-2;
|
|
|
|
}
|
2006-11-04 22:26:04 +00:00
|
|
|
else if (!statestring.CompareNoCase("LOOP"))
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
|
|
|
if (!laststate)
|
|
|
|
{
|
|
|
|
SC_ScriptError("LOOP before first state");
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
laststate->NextState=(FState*)(lastlabel+1);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2006-11-04 22:26:04 +00:00
|
|
|
const char * statestrp;
|
2006-02-24 04:48:15 +00:00
|
|
|
|
2006-10-29 11:01:00 +00:00
|
|
|
SC_MustGetString();
|
2006-02-24 04:48:15 +00:00
|
|
|
if (SC_Compare (":"))
|
|
|
|
{
|
2006-05-06 03:25:12 +00:00
|
|
|
laststate = NULL;
|
2006-02-24 04:48:15 +00:00
|
|
|
do
|
|
|
|
{
|
|
|
|
lastlabel = count;
|
2006-10-31 14:53:21 +00:00
|
|
|
AddState(statestring, (FState *) (count+1));
|
2006-11-04 22:26:04 +00:00
|
|
|
statestring = ParseStateString();
|
|
|
|
if (!statestring.CompareNoCase("GOTO"))
|
2006-05-06 03:25:12 +00:00
|
|
|
{
|
|
|
|
goto do_goto;
|
|
|
|
}
|
2006-11-04 22:26:04 +00:00
|
|
|
else if (!statestring.CompareNoCase("STOP"))
|
2006-05-07 23:55:17 +00:00
|
|
|
{
|
|
|
|
goto do_stop;
|
|
|
|
}
|
2006-02-24 04:48:15 +00:00
|
|
|
SC_MustGetString ();
|
|
|
|
} while (SC_Compare (":"));
|
|
|
|
// continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
SC_UnGet ();
|
|
|
|
|
2006-11-04 22:26:04 +00:00
|
|
|
if (statestring.Len() != 4)
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
|
|
|
SC_ScriptError ("Sprite names must be exactly 4 characters\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
memcpy(state.sprite.name, statestring, 4);
|
|
|
|
state.Misc1=state.Misc2=0;
|
2006-10-29 11:01:00 +00:00
|
|
|
state.ParameterIndex=0;
|
|
|
|
SC_MustGetString();
|
2006-11-04 22:26:04 +00:00
|
|
|
statestring = (sc_String+1);
|
2006-02-24 04:48:15 +00:00
|
|
|
statestrp = statestring;
|
|
|
|
state.Frame=(*sc_String&223)-'A';
|
|
|
|
if ((*sc_String&223)<'A' || (*sc_String&223)>']')
|
|
|
|
{
|
|
|
|
SC_ScriptError ("Frames must be A-Z, [, \\, or ]");
|
|
|
|
state.Frame=0;
|
|
|
|
}
|
|
|
|
|
|
|
|
SC_MustGetNumber();
|
|
|
|
sc_Number++;
|
|
|
|
state.Tics=sc_Number&255;
|
|
|
|
state.Misc1=(sc_Number>>8)&255;
|
|
|
|
if (state.Misc1) state.Frame|=SF_BIGTIC;
|
|
|
|
|
|
|
|
while (SC_GetString() && !sc_Crossed)
|
|
|
|
{
|
|
|
|
if (SC_Compare("BRIGHT"))
|
|
|
|
{
|
|
|
|
state.Frame|=SF_FULLBRIGHT;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (SC_Compare("OFFSET"))
|
|
|
|
{
|
|
|
|
if (state.Frame&SF_BIGTIC)
|
|
|
|
{
|
|
|
|
SC_ScriptError("You cannot use OFFSET with a state duration larger than 254!");
|
|
|
|
}
|
|
|
|
// specify a weapon offset
|
|
|
|
SC_MustGetStringName("(");
|
|
|
|
SC_MustGetNumber();
|
|
|
|
state.Misc1=sc_Number;
|
2006-11-26 12:13:12 +00:00
|
|
|
SC_MustGetStringName (",");
|
2006-02-24 04:48:15 +00:00
|
|
|
SC_MustGetNumber();
|
|
|
|
state.Misc2=sc_Number;
|
|
|
|
SC_MustGetStringName(")");
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Make the action name lowercase to satisfy the gperf hashers
|
|
|
|
strlwr (sc_String);
|
|
|
|
|
|
|
|
int minreq=count;
|
2006-11-04 22:26:04 +00:00
|
|
|
if (DoSpecialFunctions(state, !statestring.IsEmpty(), &minreq, bag))
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
|
|
|
if (minreq>minrequiredstate) minrequiredstate=minreq;
|
|
|
|
goto endofstate;
|
|
|
|
}
|
|
|
|
|
2006-12-04 23:25:59 +00:00
|
|
|
PSymbol *sym = bag.Info->Class->Symbols.FindSymbol (FName(sc_String, true), true);
|
|
|
|
if (sym != NULL && sym->SymbolType == SYM_ActionFunction)
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
2006-12-04 23:25:59 +00:00
|
|
|
PSymbolActionFunction *afd = static_cast<PSymbolActionFunction *>(sym);
|
2006-02-24 04:48:15 +00:00
|
|
|
state.Action = afd->Function;
|
2006-12-04 23:25:59 +00:00
|
|
|
if (!afd->Arguments.IsEmpty())
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
2006-12-04 23:25:59 +00:00
|
|
|
const char *params = afd->Arguments.GetChars();
|
|
|
|
int numparams = (int)afd->Arguments.Len();
|
2006-11-29 04:51:16 +00:00
|
|
|
|
2006-05-10 15:07:14 +00:00
|
|
|
int v;
|
2006-02-24 04:48:15 +00:00
|
|
|
|
|
|
|
if (!islower(*params))
|
|
|
|
{
|
|
|
|
SC_MustGetStringName("(");
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (!SC_CheckString("(")) goto endofstate;
|
|
|
|
}
|
2006-07-29 10:47:14 +00:00
|
|
|
|
|
|
|
int paramindex = PrepareStateParameters(&state, numparams);
|
2006-10-27 03:03:34 +00:00
|
|
|
int paramstart = paramindex;
|
|
|
|
bool varargs = params[numparams - 1] == '+';
|
|
|
|
|
|
|
|
if (varargs)
|
|
|
|
{
|
|
|
|
StateParameters[paramindex++] = 0;
|
|
|
|
}
|
|
|
|
|
2006-02-24 04:48:15 +00:00
|
|
|
while (*params)
|
|
|
|
{
|
|
|
|
switch(*params)
|
|
|
|
{
|
|
|
|
case 'I':
|
|
|
|
case 'i': // Integer
|
|
|
|
SC_MustGetNumber();
|
|
|
|
v=sc_Number;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'F':
|
|
|
|
case 'f': // Fixed point
|
|
|
|
SC_MustGetFloat();
|
2006-04-12 03:03:58 +00:00
|
|
|
v=fixed_t(sc_Float*FRACUNIT);
|
2006-02-24 04:48:15 +00:00
|
|
|
break;
|
|
|
|
|
2006-05-10 15:07:14 +00:00
|
|
|
|
2006-02-24 04:48:15 +00:00
|
|
|
case 'S':
|
|
|
|
case 's': // Sound name
|
|
|
|
SC_MustGetString();
|
|
|
|
v=S_FindSound(sc_String);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'M':
|
|
|
|
case 'm': // Actor name
|
|
|
|
case 'T':
|
|
|
|
case 't': // String
|
2006-10-29 11:01:00 +00:00
|
|
|
SC_SetEscape(true);
|
2006-02-24 04:48:15 +00:00
|
|
|
SC_MustGetString();
|
2006-10-29 11:01:00 +00:00
|
|
|
SC_SetEscape(false);
|
2006-05-10 15:07:14 +00:00
|
|
|
v = (int)(sc_String[0] ? FName(sc_String) : NAME_None);
|
2006-02-24 04:48:15 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case 'L':
|
|
|
|
case 'l': // Jump label
|
|
|
|
|
2006-11-05 21:46:28 +00:00
|
|
|
if (SC_CheckNumber())
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
2006-11-07 10:20:09 +00:00
|
|
|
if (strlen(statestring)>0)
|
|
|
|
{
|
|
|
|
SC_ScriptError("You cannot use A_Jump commands with a jump index on multistate definitions\n");
|
|
|
|
}
|
|
|
|
|
2006-11-05 21:46:28 +00:00
|
|
|
v=sc_Number;
|
|
|
|
if (v<1)
|
|
|
|
{
|
|
|
|
SC_ScriptError("Negative jump offsets are not allowed");
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
|
|
|
int minreq=count+v;
|
|
|
|
if (minreq>minrequiredstate) minrequiredstate=minreq;
|
|
|
|
}
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
2006-11-05 21:46:28 +00:00
|
|
|
else
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
2006-11-05 21:46:28 +00:00
|
|
|
if (JumpParameters.Size()==0) JumpParameters.Push(0);
|
|
|
|
|
|
|
|
v = -(int)JumpParameters.Size();
|
|
|
|
FString statestring = ParseStateString();
|
|
|
|
const PClass *stype=NULL;
|
|
|
|
int scope = statestring.IndexOf("::");
|
|
|
|
if (scope >= 0)
|
|
|
|
{
|
|
|
|
FName scopename = FName(statestring, scope, false);
|
|
|
|
if (scopename == NAME_Super)
|
|
|
|
{
|
|
|
|
// Super refers to the direct superclass
|
|
|
|
scopename = actor->Class->ParentClass->TypeName;
|
|
|
|
}
|
|
|
|
JumpParameters.Push(scopename);
|
|
|
|
statestring = statestring.Right(statestring.Len()-scope-2);
|
|
|
|
|
|
|
|
stype = PClass::FindClass (scopename);
|
|
|
|
if (stype == NULL)
|
|
|
|
{
|
2006-12-09 00:16:10 +00:00
|
|
|
SC_ScriptError ("%s is an unknown class.", scopename.GetChars());
|
2006-11-05 21:46:28 +00:00
|
|
|
}
|
|
|
|
if (!stype->IsDescendantOf (RUNTIME_CLASS(AActor)))
|
|
|
|
{
|
|
|
|
SC_ScriptError ("%s is not an actor class, so it has no states.", stype->TypeName.GetChars());
|
|
|
|
}
|
|
|
|
if (!stype->IsAncestorOf (actor->Class))
|
|
|
|
{
|
|
|
|
SC_ScriptError ("%s is not derived from %s so cannot access its states.",
|
|
|
|
actor->Class->TypeName.GetChars(), stype->TypeName.GetChars());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// No class name is stored. This allows 'virtual' jumps to
|
|
|
|
// labels in subclasses.
|
|
|
|
// It also means that the validity of the given state cannot
|
|
|
|
// be checked here.
|
|
|
|
JumpParameters.Push(0);
|
|
|
|
}
|
|
|
|
TArray<FName> names;
|
|
|
|
MakeStateNameList(statestring, &names);
|
|
|
|
|
|
|
|
if (stype != NULL)
|
|
|
|
{
|
|
|
|
if (!stype->ActorInfo->FindState(names.Size(), (va_list)&names[0]))
|
|
|
|
{
|
|
|
|
SC_ScriptError("Jump to unknown state '%s' in class '%s'",
|
|
|
|
statestring.GetChars(), stype->TypeName.GetChars());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
JumpParameters.Push(names.Size());
|
|
|
|
for(unsigned i=0;i<names.Size();i++)
|
|
|
|
{
|
|
|
|
JumpParameters.Push(names[i]);
|
|
|
|
}
|
|
|
|
// No offsets here. The point of jumping to labels is to avoid such things!
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'C':
|
2006-08-17 00:19:26 +00:00
|
|
|
case 'c': // Color
|
2006-02-24 04:48:15 +00:00
|
|
|
SC_MustGetString ();
|
|
|
|
if (SC_Compare("none"))
|
|
|
|
{
|
|
|
|
v = -1;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
int c = V_GetColor (NULL, sc_String);
|
2006-04-23 20:12:27 +00:00
|
|
|
// 0 needs to be the default so we have to mark the color.
|
|
|
|
v = MAKEARGB(1, RPART(c), GPART(c), BPART(c));
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'X':
|
|
|
|
case 'x':
|
2006-11-29 04:51:16 +00:00
|
|
|
v = ParseExpression (false, bag.Info->Class);
|
2006-04-11 08:36:23 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case 'Y':
|
|
|
|
case 'y':
|
2006-11-29 04:51:16 +00:00
|
|
|
v = ParseExpression (true, bag.Info->Class);
|
2006-02-24 04:48:15 +00:00
|
|
|
break;
|
2006-05-16 04:19:20 +00:00
|
|
|
|
|
|
|
default:
|
|
|
|
assert(false);
|
|
|
|
v = -1;
|
|
|
|
break;
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
2006-10-27 03:03:34 +00:00
|
|
|
StateParameters[paramindex++] = v;
|
2006-02-24 04:48:15 +00:00
|
|
|
params++;
|
2006-10-27 03:03:34 +00:00
|
|
|
if (varargs)
|
|
|
|
{
|
|
|
|
StateParameters[paramstart]++;
|
|
|
|
}
|
2006-02-24 04:48:15 +00:00
|
|
|
if (*params)
|
|
|
|
{
|
2006-10-27 03:03:34 +00:00
|
|
|
if (*params == '+')
|
|
|
|
{
|
|
|
|
if (SC_CheckString(")"))
|
|
|
|
{
|
|
|
|
goto endofstate;
|
|
|
|
}
|
|
|
|
params--;
|
|
|
|
v = 0;
|
|
|
|
StateParameters.Push(v);
|
|
|
|
}
|
|
|
|
else if ((islower(*params) || *params=='!') && SC_CheckString(")"))
|
|
|
|
{
|
|
|
|
goto endofstate;
|
|
|
|
}
|
2006-11-26 12:13:12 +00:00
|
|
|
SC_MustGetStringName (",");
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
SC_MustGetStringName(")");
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
SC_MustGetString();
|
|
|
|
if (SC_Compare("("))
|
|
|
|
{
|
|
|
|
SC_ScriptError("You cannot pass parameters to '%s'\n",sc_String);
|
|
|
|
}
|
|
|
|
SC_UnGet();
|
|
|
|
}
|
|
|
|
goto endofstate;
|
|
|
|
}
|
|
|
|
SC_ScriptError("Invalid state parameter %s\n", sc_String);
|
|
|
|
}
|
|
|
|
SC_UnGet();
|
|
|
|
endofstate:
|
|
|
|
StateArray.Push(state);
|
|
|
|
while (*statestrp)
|
|
|
|
{
|
|
|
|
int frame=((*statestrp++)&223)-'A';
|
|
|
|
|
|
|
|
if (frame<0 || frame>28)
|
|
|
|
{
|
|
|
|
SC_ScriptError ("Frames must be A-Z, [, \\, or ]");
|
|
|
|
frame=0;
|
|
|
|
}
|
|
|
|
|
2006-10-29 11:01:00 +00:00
|
|
|
state.Frame=(state.Frame&(SF_FULLBRIGHT|SF_BIGTIC))|frame;
|
2006-02-24 04:48:15 +00:00
|
|
|
StateArray.Push(state);
|
|
|
|
count++;
|
|
|
|
}
|
|
|
|
laststate=&StateArray[count];
|
|
|
|
count++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (count<=minrequiredstate)
|
|
|
|
{
|
2006-05-10 02:40:43 +00:00
|
|
|
SC_ScriptError("A_Jump offset out of range in %s", actor->Class->TypeName.GetChars());
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
2006-10-29 11:01:00 +00:00
|
|
|
SC_SetEscape(true); // re-enable escape sequences
|
2006-02-24 04:48:15 +00:00
|
|
|
return count;
|
|
|
|
}
|
|
|
|
|
2006-05-06 03:25:12 +00:00
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
// ResolveGotoLabel
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
2006-10-31 14:53:21 +00:00
|
|
|
static FState *ResolveGotoLabel (AActor *actor, const PClass *mytype, char *name)
|
2006-05-06 03:25:12 +00:00
|
|
|
{
|
2006-10-31 14:53:21 +00:00
|
|
|
const PClass *type=mytype;
|
|
|
|
FState *state;
|
2006-05-06 03:25:12 +00:00
|
|
|
char *namestart = name;
|
|
|
|
char *label, *offset, *pt;
|
|
|
|
int v;
|
|
|
|
|
|
|
|
// Check for classname
|
2006-11-04 22:26:04 +00:00
|
|
|
if ((pt = strstr (name, "::")) != NULL)
|
2006-05-06 03:25:12 +00:00
|
|
|
{
|
|
|
|
const char *classname = name;
|
|
|
|
*pt = '\0';
|
2006-11-04 22:26:04 +00:00
|
|
|
name = pt + 2;
|
2006-05-06 03:25:12 +00:00
|
|
|
|
|
|
|
// The classname may either be "Super" to identify this class's immediate
|
2006-06-21 23:22:17 +00:00
|
|
|
// superclass, or it may be the name of any class that this one derives from.
|
2006-05-06 03:25:12 +00:00
|
|
|
if (stricmp (classname, "Super") == 0)
|
|
|
|
{
|
2006-05-10 02:40:43 +00:00
|
|
|
type = type->ParentClass;
|
2006-05-06 03:25:12 +00:00
|
|
|
actor = GetDefaultByType (type);
|
|
|
|
}
|
2006-11-04 22:26:04 +00:00
|
|
|
else
|
2006-05-06 03:25:12 +00:00
|
|
|
{
|
2006-10-31 14:53:21 +00:00
|
|
|
// first check whether a state of the desired name exists
|
2006-05-10 02:40:43 +00:00
|
|
|
const PClass *stype = PClass::FindClass (classname);
|
2006-05-06 03:25:12 +00:00
|
|
|
if (stype == NULL)
|
|
|
|
{
|
|
|
|
SC_ScriptError ("%s is an unknown class.", classname);
|
|
|
|
}
|
|
|
|
if (!stype->IsDescendantOf (RUNTIME_CLASS(AActor)))
|
|
|
|
{
|
2006-05-10 02:40:43 +00:00
|
|
|
SC_ScriptError ("%s is not an actor class, so it has no states.", stype->TypeName.GetChars());
|
2006-05-06 03:25:12 +00:00
|
|
|
}
|
|
|
|
if (!stype->IsAncestorOf (type))
|
|
|
|
{
|
|
|
|
SC_ScriptError ("%s is not derived from %s so cannot access its states.",
|
2006-05-10 02:40:43 +00:00
|
|
|
type->TypeName.GetChars(), stype->TypeName.GetChars());
|
2006-05-06 03:25:12 +00:00
|
|
|
}
|
|
|
|
if (type != stype)
|
|
|
|
{
|
|
|
|
type = stype;
|
|
|
|
actor = GetDefaultByType (type);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
label = name;
|
|
|
|
// Check for offset
|
|
|
|
offset = NULL;
|
|
|
|
if ((pt = strchr (name, '+')) != NULL)
|
|
|
|
{
|
|
|
|
*pt = '\0';
|
|
|
|
offset = pt + 1;
|
|
|
|
}
|
|
|
|
v = offset ? strtol (offset, NULL, 0) : 0;
|
|
|
|
|
2006-10-31 14:53:21 +00:00
|
|
|
// Get the state's address.
|
|
|
|
if (type==mytype) state = FindState (actor, type, label);
|
|
|
|
else state = FindStateInClass (actor, type, label);
|
|
|
|
|
|
|
|
if (state != NULL)
|
2006-05-06 03:25:12 +00:00
|
|
|
{
|
2006-10-31 14:53:21 +00:00
|
|
|
state += v;
|
2006-05-06 03:25:12 +00:00
|
|
|
}
|
2006-10-31 14:53:21 +00:00
|
|
|
else if (v != 0)
|
2006-05-06 03:25:12 +00:00
|
|
|
{
|
2006-10-31 14:53:21 +00:00
|
|
|
SC_ScriptError ("Attempt to get invalid state %s from actor %s.", label, type->TypeName.GetChars());
|
2006-05-06 03:25:12 +00:00
|
|
|
}
|
2006-05-09 03:40:15 +00:00
|
|
|
delete[] namestart; // free the allocated string buffer
|
2006-05-06 03:25:12 +00:00
|
|
|
return state;
|
|
|
|
}
|
|
|
|
|
2006-02-24 04:48:15 +00:00
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
// FixStatePointers
|
|
|
|
//
|
|
|
|
// Fixes an actor's default state pointers.
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
2006-10-31 14:53:21 +00:00
|
|
|
static void FixStatePointers (FActorInfo *actor, TArray<FStateDefine> & list)
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
2006-10-31 14:53:21 +00:00
|
|
|
for(unsigned i=0;i<list.Size(); i++)
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
2006-10-31 14:53:21 +00:00
|
|
|
size_t v=(size_t)list[i].State;
|
2006-02-24 04:48:15 +00:00
|
|
|
if (v >= 1 && v < 0x10000)
|
|
|
|
{
|
2006-10-31 14:53:21 +00:00
|
|
|
list[i].State = actor->OwnedStates + v - 1;
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
2006-10-31 14:53:21 +00:00
|
|
|
if (list[i].Children.Size() > 0) FixStatePointers(actor, list[i].Children);
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
// FixStatePointersAgain
|
|
|
|
//
|
|
|
|
// Resolves an actor's state pointers that were specified as jumps.
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
2006-10-31 14:53:21 +00:00
|
|
|
static void FixStatePointersAgain (FActorInfo *actor, AActor *defaults, TArray<FStateDefine> & list)
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
2006-10-31 14:53:21 +00:00
|
|
|
for(unsigned i=0;i<list.Size(); i++)
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
2006-10-31 14:53:21 +00:00
|
|
|
if (list[i].State != NULL && FState::StaticFindStateOwner (list[i].State, actor) == NULL)
|
2006-05-06 03:25:12 +00:00
|
|
|
{ // It's not a valid state, so it must be a label string. Resolve it.
|
2006-10-31 14:53:21 +00:00
|
|
|
list[i].State = ResolveGotoLabel (defaults, actor->Class, (char *)list[i].State);
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
2006-10-31 14:53:21 +00:00
|
|
|
if (list[i].Children.Size() > 0) FixStatePointersAgain(actor, defaults, list[i].Children);
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-10-31 14:53:21 +00:00
|
|
|
|
2006-02-24 04:48:15 +00:00
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
// FinishStates
|
|
|
|
// copies a state block and fixes all state links
|
|
|
|
//
|
|
|
|
//==========================================================================
|
2006-10-31 14:53:21 +00:00
|
|
|
|
2006-02-24 04:48:15 +00:00
|
|
|
static int FinishStates (FActorInfo *actor, AActor *defaults, Baggage &bag)
|
|
|
|
{
|
2006-10-31 14:53:21 +00:00
|
|
|
static int c=0;
|
2006-02-24 04:48:15 +00:00
|
|
|
int count = StateArray.Size();
|
|
|
|
|
2006-05-06 03:25:12 +00:00
|
|
|
if (count > 0)
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
2006-05-09 03:40:15 +00:00
|
|
|
FState *realstates = new FState[count];
|
|
|
|
int i;
|
|
|
|
int currange;
|
|
|
|
|
2006-05-06 03:25:12 +00:00
|
|
|
memcpy(realstates, &StateArray[0], count*sizeof(FState));
|
|
|
|
actor->OwnedStates = realstates;
|
|
|
|
actor->NumOwnedStates = count;
|
2006-02-24 04:48:15 +00:00
|
|
|
|
2006-05-06 03:25:12 +00:00
|
|
|
// adjust the state pointers
|
|
|
|
// In the case new states are added these must be adjusted, too!
|
2006-10-31 14:53:21 +00:00
|
|
|
FixStatePointers (actor, StateLabels);
|
2006-02-24 04:48:15 +00:00
|
|
|
|
2006-05-06 03:25:12 +00:00
|
|
|
for(i = currange = 0; i < count; i++)
|
|
|
|
{
|
|
|
|
// resolve labels and jumps
|
|
|
|
switch((ptrdiff_t)realstates[i].NextState)
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
2006-05-06 03:25:12 +00:00
|
|
|
case 0: // next
|
|
|
|
realstates[i].NextState = (i < count-1 ? &realstates[i+1] : &realstates[0]);
|
|
|
|
break;
|
2006-02-24 04:48:15 +00:00
|
|
|
|
2006-05-06 03:25:12 +00:00
|
|
|
case -1: // stop
|
|
|
|
realstates[i].NextState = NULL;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case -2: // wait
|
|
|
|
realstates[i].NextState = &realstates[i];
|
|
|
|
break;
|
|
|
|
|
|
|
|
default: // loop
|
|
|
|
if ((size_t)realstates[i].NextState < 0x10000)
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
2006-05-06 03:25:12 +00:00
|
|
|
realstates[i].NextState = &realstates[(size_t)realstates[i].NextState-1];
|
|
|
|
}
|
|
|
|
else // goto
|
|
|
|
{
|
|
|
|
realstates[i].NextState = ResolveGotoLabel (defaults, bag.Info->Class, (char *)realstates[i].NextState);
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
StateArray.Clear ();
|
2006-05-06 03:25:12 +00:00
|
|
|
|
|
|
|
// Fix state pointers that are gotos
|
2006-10-31 14:53:21 +00:00
|
|
|
FixStatePointersAgain (actor, defaults, StateLabels);
|
2006-05-06 03:25:12 +00:00
|
|
|
|
2006-02-24 04:48:15 +00:00
|
|
|
return count;
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
// For getting a state address from the parent
|
2006-10-31 14:53:21 +00:00
|
|
|
// No attempts have been made to add new functionality here
|
|
|
|
// This is strictly for keeping compatibility with old WADs!
|
2006-02-24 04:48:15 +00:00
|
|
|
//
|
|
|
|
//==========================================================================
|
2006-10-31 14:53:21 +00:00
|
|
|
static FState *CheckState(PClass *type)
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
2006-10-31 14:53:21 +00:00
|
|
|
int v=0;
|
|
|
|
|
2006-02-24 04:48:15 +00:00
|
|
|
if (SC_GetString() && !sc_Crossed)
|
|
|
|
{
|
|
|
|
if (SC_Compare("0")) return NULL;
|
|
|
|
else if (SC_Compare("PARENT"))
|
|
|
|
{
|
2006-10-31 14:53:21 +00:00
|
|
|
FState * state = NULL;
|
2006-02-24 04:48:15 +00:00
|
|
|
SC_MustGetString();
|
|
|
|
|
2006-10-31 14:53:21 +00:00
|
|
|
FActorInfo * info = type->ParentClass->ActorInfo;
|
2006-02-24 04:48:15 +00:00
|
|
|
|
2006-10-31 14:53:21 +00:00
|
|
|
if (info != NULL)
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
2006-10-31 14:53:21 +00:00
|
|
|
state = info->FindStateExact(1, (int)FName(sc_String));
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (SC_GetString ())
|
|
|
|
{
|
|
|
|
if (SC_Compare ("+"))
|
|
|
|
{
|
|
|
|
SC_MustGetNumber ();
|
|
|
|
v = sc_Number;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
SC_UnGet ();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-10-31 14:53:21 +00:00
|
|
|
if (state == NULL && v==0) return NULL;
|
2006-02-24 04:48:15 +00:00
|
|
|
|
2006-10-31 14:53:21 +00:00
|
|
|
if (v!=0 && state==NULL)
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
2006-05-10 02:40:43 +00:00
|
|
|
SC_ScriptError("Attempt to get invalid state from actor %s\n", type->ParentClass->TypeName.GetChars());
|
2006-02-24 04:48:15 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
2006-10-31 14:53:21 +00:00
|
|
|
state+=v;
|
|
|
|
return state;
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
else SC_ScriptError("Invalid state assignment");
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2006-07-31 10:22:53 +00:00
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
// Checks for a numeric parameter which may or may not be preceded by a comma
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
static bool CheckNumParm()
|
|
|
|
{
|
|
|
|
if (SC_CheckString(","))
|
|
|
|
{
|
|
|
|
SC_MustGetNumber();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return !!SC_CheckNumber();
|
|
|
|
}
|
|
|
|
}
|
2006-02-24 04:48:15 +00:00
|
|
|
|
2006-07-31 10:22:53 +00:00
|
|
|
static bool CheckFloatParm()
|
|
|
|
{
|
|
|
|
if (SC_CheckString(","))
|
|
|
|
{
|
|
|
|
SC_MustGetFloat();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return !!SC_CheckFloat();
|
|
|
|
}
|
|
|
|
}
|
2006-02-24 04:48:15 +00:00
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
// Handle actor properties
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
void ParseActorProperties (Baggage &bag)
|
|
|
|
{
|
2006-05-10 02:40:43 +00:00
|
|
|
const PClass *info;
|
2006-02-24 04:48:15 +00:00
|
|
|
const ActorProps *prop;
|
|
|
|
|
2006-11-26 12:13:12 +00:00
|
|
|
SC_MustGetStringName ("{");
|
|
|
|
while (!SC_CheckString ("}"))
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
2006-05-09 08:58:30 +00:00
|
|
|
if (sc_End)
|
|
|
|
{
|
|
|
|
SC_ScriptError("Unexpected end of file encountered");
|
|
|
|
}
|
|
|
|
|
2006-02-24 04:48:15 +00:00
|
|
|
SC_GetString ();
|
|
|
|
strlwr (sc_String);
|
|
|
|
|
|
|
|
// Walk the ancestors of this type and see if any of them know
|
|
|
|
// about the property.
|
|
|
|
info = bag.Info->Class;
|
|
|
|
|
2006-05-03 22:45:01 +00:00
|
|
|
FString propname = sc_String;
|
2006-02-24 04:48:15 +00:00
|
|
|
|
2006-04-11 08:36:23 +00:00
|
|
|
if (sc_String[0]!='-' && sc_String[0]!='+')
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
2006-04-09 19:34:35 +00:00
|
|
|
if (SC_CheckString ("."))
|
|
|
|
{
|
|
|
|
SC_MustGetString ();
|
|
|
|
propname += '.';
|
|
|
|
strlwr (sc_String);
|
|
|
|
propname += sc_String;
|
|
|
|
}
|
2006-04-11 08:36:23 +00:00
|
|
|
else
|
2006-04-09 19:34:35 +00:00
|
|
|
{
|
|
|
|
SC_UnGet ();
|
|
|
|
}
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
prop = is_actorprop (propname.GetChars());
|
|
|
|
|
|
|
|
if (prop != NULL)
|
|
|
|
{
|
|
|
|
if (!info->IsDescendantOf(prop->type))
|
|
|
|
{
|
2006-05-10 02:40:43 +00:00
|
|
|
SC_ScriptError("\"%s\" requires an actor of type \"%s\"\n", propname.GetChars(), prop->type->TypeName.GetChars());
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2006-05-10 02:40:43 +00:00
|
|
|
prop->Handler ((AActor *)bag.Info->Class->Defaults, bag);
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
SC_ScriptError("\"%s\" is an unknown actor property\n", propname.GetChars());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
// Reads an actor definition
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
void ProcessActor(void (*process)(FState *, int))
|
|
|
|
{
|
|
|
|
FActorInfo * info=NULL;
|
|
|
|
AActor * defaults;
|
|
|
|
Baggage bag;
|
|
|
|
|
|
|
|
try
|
|
|
|
{
|
|
|
|
FActorInfo * parent;
|
|
|
|
|
2006-06-21 23:22:17 +00:00
|
|
|
|
2006-02-24 04:48:15 +00:00
|
|
|
info=CreateNewActor(&parent, &bag);
|
2006-05-10 02:40:43 +00:00
|
|
|
defaults=(AActor*)info->Class->Defaults;
|
2006-02-24 04:48:15 +00:00
|
|
|
bag.StateSet = false;
|
|
|
|
bag.DropItemSet = false;
|
|
|
|
bag.CurrentState = 0;
|
|
|
|
|
|
|
|
ParseActorProperties (bag);
|
|
|
|
FinishStates (info, defaults, bag);
|
2006-10-31 14:53:21 +00:00
|
|
|
InstallStates(info, defaults);
|
2006-02-24 04:48:15 +00:00
|
|
|
process(info->OwnedStates, info->NumOwnedStates);
|
|
|
|
if (bag.DropItemSet)
|
|
|
|
{
|
|
|
|
if (bag.DropItemList == NULL)
|
|
|
|
{
|
|
|
|
if (info->Class->Meta.GetMetaInt (ACMETA_DropItems) != 0)
|
|
|
|
{
|
|
|
|
info->Class->Meta.SetMetaInt (ACMETA_DropItems, 0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
info->Class->Meta.SetMetaInt (ACMETA_DropItems,
|
|
|
|
DropItemList.Push (bag.DropItemList) + 1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (info->Class->IsDescendantOf (RUNTIME_CLASS(AInventory)))
|
|
|
|
{
|
|
|
|
defaults->flags |= MF_SPECIAL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
catch(CRecoverableError & e)
|
|
|
|
{
|
|
|
|
throw e;
|
|
|
|
}
|
|
|
|
// I think this is better than a crash log.
|
|
|
|
#ifndef _DEBUG
|
|
|
|
catch (...)
|
|
|
|
{
|
|
|
|
if (info)
|
2006-05-10 04:12:43 +00:00
|
|
|
SC_ScriptError("Unexpected error during parsing of actor %s", info->Class->TypeName.GetChars());
|
2006-02-24 04:48:15 +00:00
|
|
|
else
|
|
|
|
SC_ScriptError("Unexpected error during parsing of actor definitions");
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
SC_SetCMode (false);
|
|
|
|
}
|
|
|
|
|
2006-05-06 03:25:12 +00:00
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
// StatePropertyIsDeprecated
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
static void StatePropertyIsDeprecated (const char *actorname, const char *prop)
|
|
|
|
{
|
2006-11-05 15:49:54 +00:00
|
|
|
/*
|
2006-05-06 03:25:12 +00:00
|
|
|
static bool warned = false;
|
|
|
|
|
2006-11-05 15:49:54 +00:00
|
|
|
Printf (TEXTCOLOR_YELLOW "In actor %s, the %s property is deprecated.\n", actorname, prop);
|
2006-05-06 03:25:12 +00:00
|
|
|
if (!warned)
|
|
|
|
{
|
|
|
|
warned = true;
|
|
|
|
Printf (TEXTCOLOR_YELLOW "Instead of \"%s <state>\", add this to the actor's States block:\n"
|
|
|
|
TEXTCOLOR_YELLOW " %s:\n"
|
|
|
|
TEXTCOLOR_YELLOW " Goto <state>\n", prop, prop);
|
|
|
|
}
|
2006-11-05 15:49:54 +00:00
|
|
|
*/
|
2006-05-06 03:25:12 +00:00
|
|
|
}
|
|
|
|
|
2006-02-24 04:48:15 +00:00
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
// Property parsers
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
2006-11-29 04:51:16 +00:00
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
// ActorConstDef
|
|
|
|
//
|
|
|
|
// Parses a constant definition.
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
static void ActorConstDef (AActor *defaults, Baggage &bag)
|
|
|
|
{
|
|
|
|
// Read the type and make sure it's int.
|
|
|
|
// (Maybe there will be other types later.)
|
|
|
|
SC_MustGetToken(TK_Int);
|
|
|
|
SC_MustGetToken(TK_Identifier);
|
|
|
|
FName symname = sc_Name;
|
|
|
|
SC_MustGetToken('=');
|
|
|
|
int expr = ParseExpression (false, bag.Info->Class);
|
|
|
|
SC_MustGetToken(';');
|
|
|
|
|
|
|
|
int val = EvalExpressionI (expr, NULL, bag.Info->Class);
|
|
|
|
PSymbolConst *sym = new PSymbolConst;
|
|
|
|
sym->SymbolName = symname;
|
|
|
|
sym->SymbolType = SYM_Const;
|
|
|
|
sym->Value = val;
|
|
|
|
if (bag.Info->Class->Symbols.AddSymbol (sym) == NULL)
|
|
|
|
{
|
|
|
|
delete sym;
|
|
|
|
SC_ScriptError ("'%s' is already defined in class '%s'.",
|
|
|
|
symname.GetChars(), bag.Info->Class->TypeName.GetChars());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-11-29 16:20:22 +00:00
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
// ParseGlobalConst
|
|
|
|
//
|
|
|
|
// Parses a constant outside an actor definition
|
|
|
|
// These will be inserted into AActor's symbol table
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
void ParseGlobalConst()
|
|
|
|
{
|
|
|
|
Baggage bag;
|
|
|
|
|
|
|
|
bag.Info = RUNTIME_CLASS(AActor)->ActorInfo;
|
|
|
|
ActorConstDef(GetDefault<AActor>(), bag);
|
|
|
|
}
|
|
|
|
|
2006-11-29 04:51:16 +00:00
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
// ActorActionDef
|
|
|
|
//
|
2006-12-04 23:25:59 +00:00
|
|
|
// Parses an action function definition. A lot of this is essentially
|
|
|
|
// documentation in the declaration for when I have a proper language
|
|
|
|
// ready.
|
2006-11-29 04:51:16 +00:00
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
static void ActorActionDef (AActor *defaults, Baggage &bag)
|
|
|
|
{
|
|
|
|
#define OPTIONAL 1
|
|
|
|
#define EVAL 2
|
|
|
|
#define EVALNOT 4
|
|
|
|
|
2006-12-04 23:25:59 +00:00
|
|
|
AFuncDesc *afd;
|
2006-11-29 04:51:16 +00:00
|
|
|
FName funcname;
|
|
|
|
FString args;
|
|
|
|
|
2006-12-04 23:25:59 +00:00
|
|
|
SC_MustGetToken(TK_Native);
|
2006-11-29 04:51:16 +00:00
|
|
|
SC_MustGetToken(TK_Identifier);
|
|
|
|
funcname = sc_Name;
|
2006-12-04 23:25:59 +00:00
|
|
|
afd = FindFunction(sc_String);
|
|
|
|
if (afd == NULL)
|
|
|
|
{
|
|
|
|
SC_ScriptError ("The function '%s' has not been exported from the executable.", sc_String);
|
|
|
|
}
|
2006-11-29 04:51:16 +00:00
|
|
|
SC_MustGetToken('(');
|
2006-12-01 01:17:45 +00:00
|
|
|
if (!SC_CheckToken(')'))
|
2006-11-29 04:51:16 +00:00
|
|
|
{
|
2006-12-01 01:17:45 +00:00
|
|
|
while (sc_TokenType != ')')
|
2006-11-29 04:51:16 +00:00
|
|
|
{
|
2006-12-01 01:17:45 +00:00
|
|
|
int flags = 0;
|
|
|
|
char type = '@';
|
|
|
|
|
|
|
|
// Retrieve flags before type name
|
|
|
|
for (;;)
|
2006-11-29 04:51:16 +00:00
|
|
|
{
|
2006-12-01 01:17:45 +00:00
|
|
|
if (SC_CheckToken(TK_Optional))
|
|
|
|
{
|
|
|
|
flags |= OPTIONAL;
|
|
|
|
}
|
|
|
|
else if (SC_CheckToken(TK_Eval))
|
|
|
|
{
|
|
|
|
flags |= EVAL;
|
|
|
|
}
|
|
|
|
else if (SC_CheckToken(TK_EvalNot))
|
|
|
|
{
|
|
|
|
flags |= EVALNOT;
|
|
|
|
}
|
|
|
|
else if (SC_CheckToken(TK_Coerce) || SC_CheckToken(TK_Native))
|
|
|
|
{
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
2006-11-29 04:51:16 +00:00
|
|
|
}
|
2006-12-04 23:25:59 +00:00
|
|
|
// Read the variable type
|
|
|
|
SC_MustGetAnyToken();
|
2006-12-01 01:17:45 +00:00
|
|
|
switch (sc_TokenType)
|
2006-11-29 04:51:16 +00:00
|
|
|
{
|
2006-12-01 01:17:45 +00:00
|
|
|
case TK_Bool: type = 'i'; break;
|
|
|
|
case TK_Int: type = 'i'; break;
|
|
|
|
case TK_Float: type = 'f'; break;
|
|
|
|
case TK_Sound: type = 's'; break;
|
|
|
|
case TK_String: type = 't'; break;
|
|
|
|
case TK_Name: type = 't'; break;
|
|
|
|
case TK_State: type = 'l'; break;
|
|
|
|
case TK_Color: type = 'c'; break;
|
|
|
|
case TK_Class:
|
|
|
|
SC_MustGetToken('<');
|
2006-12-04 23:25:59 +00:00
|
|
|
SC_MustGetToken(TK_Identifier); // Skip class name, since the parser doesn't care
|
2006-12-01 01:17:45 +00:00
|
|
|
SC_MustGetToken('>');
|
|
|
|
type = 'm';
|
|
|
|
break;
|
|
|
|
case TK_Ellipsis:
|
|
|
|
type = '+';
|
|
|
|
SC_MustGetToken(')');
|
|
|
|
SC_UnGet();
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
SC_ScriptError ("Unknown variable type %s", SC_TokenName(sc_TokenType, sc_String).GetChars());
|
|
|
|
break;
|
2006-11-29 04:51:16 +00:00
|
|
|
}
|
2006-12-04 23:25:59 +00:00
|
|
|
// Read the optional variable name
|
|
|
|
if (!SC_CheckToken(',') && !SC_CheckToken(')'))
|
|
|
|
{
|
|
|
|
SC_MustGetToken(TK_Identifier);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
SC_UnGet();
|
|
|
|
}
|
|
|
|
// If eval or evalnot were a flag, hey the decorate parser doesn't actually care about the type.
|
2006-12-01 01:17:45 +00:00
|
|
|
if (flags & EVALNOT)
|
2006-11-29 04:51:16 +00:00
|
|
|
{
|
2006-12-01 01:17:45 +00:00
|
|
|
type = 'y';
|
2006-11-29 04:51:16 +00:00
|
|
|
}
|
2006-12-01 01:17:45 +00:00
|
|
|
else if (flags & EVAL)
|
2006-11-29 04:51:16 +00:00
|
|
|
{
|
2006-12-01 01:17:45 +00:00
|
|
|
type = 'x';
|
2006-11-29 04:51:16 +00:00
|
|
|
}
|
2006-12-04 23:25:59 +00:00
|
|
|
if (!(flags & OPTIONAL) && type != '+')
|
2006-11-29 04:51:16 +00:00
|
|
|
{
|
2006-12-01 01:17:45 +00:00
|
|
|
type -= 'a' - 'A';
|
2006-11-29 04:51:16 +00:00
|
|
|
}
|
2006-12-01 01:17:45 +00:00
|
|
|
#undef OPTIONAL
|
|
|
|
#undef EVAL
|
|
|
|
#undef EVALNOT
|
|
|
|
args += type;
|
2006-11-29 04:51:16 +00:00
|
|
|
SC_MustGetAnyToken();
|
2006-12-01 01:17:45 +00:00
|
|
|
if (sc_TokenType != ',' && sc_TokenType != ')')
|
2006-11-29 04:51:16 +00:00
|
|
|
{
|
2006-12-01 01:17:45 +00:00
|
|
|
SC_ScriptError ("Expected ',' or ')' but got %s instead", SC_TokenName(sc_TokenType, sc_String).GetChars());
|
2006-11-29 04:51:16 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2006-12-01 01:17:45 +00:00
|
|
|
SC_MustGetToken(';');
|
2006-11-29 04:51:16 +00:00
|
|
|
PSymbolActionFunction *sym = new PSymbolActionFunction;
|
|
|
|
sym->SymbolName = funcname;
|
|
|
|
sym->SymbolType = SYM_ActionFunction;
|
|
|
|
sym->Arguments = args;
|
2006-12-04 23:25:59 +00:00
|
|
|
sym->Function = afd->Function;
|
2006-11-29 04:51:16 +00:00
|
|
|
if (bag.Info->Class->Symbols.AddSymbol (sym) == NULL)
|
|
|
|
{
|
|
|
|
delete sym;
|
|
|
|
SC_ScriptError ("'%s' is already defined in class '%s'.",
|
|
|
|
funcname.GetChars(), bag.Info->Class->TypeName.GetChars());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-02-24 04:48:15 +00:00
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
static void ActorSkipSuper (AActor *defaults, Baggage &bag)
|
|
|
|
{
|
|
|
|
ResetActor(defaults, &bag);
|
|
|
|
}
|
|
|
|
|
2006-04-30 21:49:18 +00:00
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
static void ActorGame (AActor *defaults, Baggage &bag)
|
|
|
|
{
|
|
|
|
SC_MustGetString ();
|
|
|
|
if (SC_Compare ("Doom"))
|
|
|
|
{
|
|
|
|
bag.Info->GameFilter |= GAME_Doom;
|
|
|
|
}
|
|
|
|
else if (SC_Compare ("Heretic"))
|
|
|
|
{
|
|
|
|
bag.Info->GameFilter |= GAME_Heretic;
|
|
|
|
}
|
|
|
|
else if (SC_Compare ("Hexen"))
|
|
|
|
{
|
|
|
|
bag.Info->GameFilter |= GAME_Hexen;
|
|
|
|
}
|
|
|
|
else if (SC_Compare ("Raven"))
|
|
|
|
{
|
|
|
|
bag.Info->GameFilter |= GAME_Raven;
|
|
|
|
}
|
|
|
|
else if (SC_Compare ("Strife"))
|
|
|
|
{
|
|
|
|
bag.Info->GameFilter |= GAME_Strife;
|
|
|
|
}
|
|
|
|
else if (SC_Compare ("Any"))
|
|
|
|
{
|
|
|
|
bag.Info->GameFilter = GAME_Any;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
SC_ScriptError ("Unknown game type %s", sc_String);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-02-24 04:48:15 +00:00
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
static void ActorSpawnID (AActor *defaults, Baggage &bag)
|
|
|
|
{
|
|
|
|
SC_MustGetNumber();
|
|
|
|
if (sc_Number<0 || sc_Number>255)
|
|
|
|
{
|
|
|
|
SC_ScriptError ("SpawnID must be in the range [0,255]");
|
|
|
|
}
|
|
|
|
else bag.Info->SpawnID=(BYTE)sc_Number;
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
static void ActorConversationID (AActor *defaults, Baggage &bag)
|
|
|
|
{
|
2006-05-07 00:27:22 +00:00
|
|
|
int convid;
|
|
|
|
|
2006-02-24 04:48:15 +00:00
|
|
|
SC_MustGetNumber();
|
2006-05-07 00:27:22 +00:00
|
|
|
convid = sc_Number;
|
|
|
|
|
|
|
|
// Handling for Strife teaser IDs - only of meaning for the standard items
|
|
|
|
// as PWADs cannot be loaded with the teasers.
|
|
|
|
if (SC_CheckString(","))
|
|
|
|
{
|
|
|
|
SC_MustGetNumber();
|
|
|
|
if ((gameinfo.flags & (GI_SHAREWARE|GI_TEASER2)) == (GI_SHAREWARE))
|
|
|
|
convid=sc_Number;
|
|
|
|
|
|
|
|
SC_MustGetStringName(",");
|
|
|
|
SC_MustGetNumber();
|
|
|
|
if ((gameinfo.flags & (GI_SHAREWARE|GI_TEASER2)) == (GI_SHAREWARE|GI_TEASER2))
|
|
|
|
convid=sc_Number;
|
|
|
|
|
|
|
|
if (convid==-1) return;
|
|
|
|
}
|
2006-06-11 11:28:48 +00:00
|
|
|
if (convid<0 || convid>1000)
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
2006-06-11 11:28:48 +00:00
|
|
|
SC_ScriptError ("ConversationID must be in the range [0,1000]");
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
2006-05-07 00:27:22 +00:00
|
|
|
else StrifeTypes[convid] = bag.Info->Class;
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
static void ActorTag (AActor *defaults, Baggage &bag)
|
|
|
|
{
|
|
|
|
SC_MustGetString();
|
|
|
|
bag.Info->Class->Meta.SetMetaString(AMETA_StrifeName, sc_String);
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
static void ActorHealth (AActor *defaults, Baggage &bag)
|
|
|
|
{
|
|
|
|
SC_MustGetNumber();
|
|
|
|
defaults->health=sc_Number;
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
static void ActorGibHealth (AActor *defaults, Baggage &bag)
|
|
|
|
{
|
|
|
|
SC_MustGetNumber();
|
|
|
|
bag.Info->Class->Meta.SetMetaInt (AMETA_GibHealth, sc_Number);
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
static void ActorWoundHealth (AActor *defaults, Baggage &bag)
|
|
|
|
{
|
|
|
|
SC_MustGetNumber();
|
|
|
|
bag.Info->Class->Meta.SetMetaInt (AMETA_WoundHealth, sc_Number);
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
static void ActorReactionTime (AActor *defaults, Baggage &bag)
|
|
|
|
{
|
|
|
|
SC_MustGetNumber();
|
|
|
|
defaults->reactiontime=sc_Number;
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
static void ActorPainChance (AActor *defaults, Baggage &bag)
|
|
|
|
{
|
|
|
|
SC_MustGetNumber();
|
|
|
|
defaults->PainChance=sc_Number;
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
static void ActorDamage (AActor *defaults, Baggage &bag)
|
|
|
|
{
|
- Added the ACS commands
ReplaceTextures (str old_texture, str new_texture, optional bool not_lower,
optional bool not_mid, optional bool not_upper, optional bool not_floor,
optional bool not_ceiling); and
SectorDamage (int tag, int amount, str type, bool players_only, bool in_air,
str protection_item, bool subclasses_okay);
- Added the vid_nowidescreen cvar to disable widescreen aspect ratio
correction. When this is enabled, the only display ratio available is 4:3
(and 5:4 if vid_tft is set).
- Added support for setting an actor's damage property to an expression
through decorate. Just enclose it within parentheses, and the expression
will be evaluated exactly as-is without the normal Doom damage calculation.
So if you want something that does exactly 6 damage, use a "Damage (6)"
property. To deal normal Doom missile damage, you can use
"Damage (random(1,8)*6)" instead of "Damage 6".
- Moved InvFirst and InvSel into APlayerPawn so that they can be consistantly
maintained by ObtainInventory.
SVN r288 (trunk)
2006-08-12 02:30:57 +00:00
|
|
|
// Damage can either be a single number, in which case it is subject
|
|
|
|
// to the original damage calculation rules. Or, it can be an expression
|
|
|
|
// and will be calculated as-is, ignoring the original rules. For
|
|
|
|
// compatibility reasons, expressions must be enclosed within
|
|
|
|
// parentheses.
|
|
|
|
|
|
|
|
if (SC_CheckString ("("))
|
|
|
|
{
|
2006-11-29 04:51:16 +00:00
|
|
|
defaults->Damage = 0x40000000 | ParseExpression (false, bag.Info->Class);
|
2006-09-17 10:43:51 +00:00
|
|
|
SC_MustGetStringName(")");
|
- Added the ACS commands
ReplaceTextures (str old_texture, str new_texture, optional bool not_lower,
optional bool not_mid, optional bool not_upper, optional bool not_floor,
optional bool not_ceiling); and
SectorDamage (int tag, int amount, str type, bool players_only, bool in_air,
str protection_item, bool subclasses_okay);
- Added the vid_nowidescreen cvar to disable widescreen aspect ratio
correction. When this is enabled, the only display ratio available is 4:3
(and 5:4 if vid_tft is set).
- Added support for setting an actor's damage property to an expression
through decorate. Just enclose it within parentheses, and the expression
will be evaluated exactly as-is without the normal Doom damage calculation.
So if you want something that does exactly 6 damage, use a "Damage (6)"
property. To deal normal Doom missile damage, you can use
"Damage (random(1,8)*6)" instead of "Damage 6".
- Moved InvFirst and InvSel into APlayerPawn so that they can be consistantly
maintained by ObtainInventory.
SVN r288 (trunk)
2006-08-12 02:30:57 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
SC_MustGetNumber ();
|
|
|
|
defaults->Damage = sc_Number;
|
|
|
|
}
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
static void ActorSpeed (AActor *defaults, Baggage &bag)
|
|
|
|
{
|
|
|
|
SC_MustGetFloat();
|
|
|
|
defaults->Speed=fixed_t(sc_Float*FRACUNIT);
|
|
|
|
}
|
|
|
|
|
2006-05-14 14:30:13 +00:00
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
static void ActorFloatSpeed (AActor *defaults, Baggage &bag)
|
|
|
|
{
|
|
|
|
SC_MustGetFloat();
|
|
|
|
defaults->FloatSpeed=fixed_t(sc_Float*FRACUNIT);
|
|
|
|
}
|
|
|
|
|
2006-02-24 04:48:15 +00:00
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
static void ActorRadius (AActor *defaults, Baggage &bag)
|
|
|
|
{
|
|
|
|
SC_MustGetFloat();
|
|
|
|
defaults->radius=fixed_t(sc_Float*FRACUNIT);
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
static void ActorHeight (AActor *defaults, Baggage &bag)
|
|
|
|
{
|
|
|
|
SC_MustGetFloat();
|
|
|
|
defaults->height=fixed_t(sc_Float*FRACUNIT);
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
static void ActorMass (AActor *defaults, Baggage &bag)
|
|
|
|
{
|
|
|
|
SC_MustGetNumber();
|
|
|
|
defaults->Mass=sc_Number;
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
static void ActorXScale (AActor *defaults, Baggage &bag)
|
|
|
|
{
|
|
|
|
SC_MustGetFloat();
|
2006-11-14 16:54:02 +00:00
|
|
|
defaults->scaleY = FLOAT2FIXED(sc_Float);
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
static void ActorYScale (AActor *defaults, Baggage &bag)
|
|
|
|
{
|
|
|
|
SC_MustGetFloat();
|
2006-11-14 16:54:02 +00:00
|
|
|
defaults->scaleY = FLOAT2FIXED(sc_Float);
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
static void ActorScale (AActor *defaults, Baggage &bag)
|
|
|
|
{
|
|
|
|
SC_MustGetFloat();
|
2006-11-14 16:54:02 +00:00
|
|
|
defaults->scaleX= defaults->scaleY = FLOAT2FIXED(sc_Float);
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
|
2006-12-02 15:38:50 +00:00
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
static void ActorArgs (AActor *defaults, Baggage &bag)
|
|
|
|
{
|
|
|
|
for (int i=0;i<5;i++)
|
|
|
|
{
|
|
|
|
SC_MustGetNumber();
|
|
|
|
defaults->args[i] = sc_Number;
|
|
|
|
if (i < 4 && !SC_CheckToken(',')) break;
|
|
|
|
}
|
|
|
|
defaults->flags2|=MF2_ARGSDEFINED;
|
|
|
|
}
|
|
|
|
|
2006-02-24 04:48:15 +00:00
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
static void ActorSeeSound (AActor *defaults, Baggage &bag)
|
|
|
|
{
|
|
|
|
SC_MustGetString();
|
|
|
|
defaults->SeeSound=S_FindSound(sc_String);
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
static void ActorAttackSound (AActor *defaults, Baggage &bag)
|
|
|
|
{
|
|
|
|
SC_MustGetString();
|
|
|
|
defaults->AttackSound=S_FindSound(sc_String);
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
static void ActorPainSound (AActor *defaults, Baggage &bag)
|
|
|
|
{
|
|
|
|
SC_MustGetString();
|
|
|
|
defaults->PainSound=S_FindSound(sc_String);
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
static void ActorDeathSound (AActor *defaults, Baggage &bag)
|
|
|
|
{
|
|
|
|
SC_MustGetString();
|
|
|
|
defaults->DeathSound=S_FindSound(sc_String);
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
static void ActorActiveSound (AActor *defaults, Baggage &bag)
|
|
|
|
{
|
|
|
|
SC_MustGetString();
|
|
|
|
defaults->ActiveSound=S_FindSound(sc_String);
|
|
|
|
}
|
|
|
|
|
2006-11-27 00:01:30 +00:00
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
static void ActorHowlSound (AActor *defaults, Baggage &bag)
|
|
|
|
{
|
|
|
|
SC_MustGetString();
|
|
|
|
bag.Info->Class->Meta.SetMetaInt (AMETA_HowlSound, S_FindSound(sc_String));
|
|
|
|
}
|
|
|
|
|
2006-02-24 04:48:15 +00:00
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
static void ActorDropItem (AActor *defaults, Baggage &bag)
|
|
|
|
{
|
|
|
|
// create a linked list of dropitems
|
|
|
|
if (!bag.DropItemSet)
|
|
|
|
{
|
|
|
|
bag.DropItemSet = true;
|
|
|
|
bag.DropItemList = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
FDropItem * di=new FDropItem;
|
|
|
|
|
|
|
|
SC_MustGetString();
|
2006-05-09 03:40:15 +00:00
|
|
|
di->Name=sc_String;
|
2006-02-24 04:48:15 +00:00
|
|
|
di->probability=255;
|
|
|
|
di->amount=-1;
|
2006-07-31 10:22:53 +00:00
|
|
|
|
|
|
|
if (CheckNumParm())
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
|
|
|
di->probability=sc_Number;
|
2006-07-31 10:22:53 +00:00
|
|
|
if (CheckNumParm())
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
|
|
|
di->amount=sc_Number;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
di->Next = bag.DropItemList;
|
|
|
|
bag.DropItemList = di;
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
static void ActorSpawnState (AActor *defaults, Baggage &bag)
|
|
|
|
{
|
2006-05-10 02:40:43 +00:00
|
|
|
StatePropertyIsDeprecated (bag.Info->Class->TypeName.GetChars(), "Spawn");
|
2006-10-31 14:53:21 +00:00
|
|
|
AddState("Spawn", CheckState ( bag.Info->Class));
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
static void ActorSeeState (AActor *defaults, Baggage &bag)
|
|
|
|
{
|
2006-05-10 02:40:43 +00:00
|
|
|
StatePropertyIsDeprecated (bag.Info->Class->TypeName.GetChars(), "See");
|
2006-10-31 14:53:21 +00:00
|
|
|
AddState("See", CheckState ( bag.Info->Class));
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
static void ActorMeleeState (AActor *defaults, Baggage &bag)
|
|
|
|
{
|
2006-05-10 02:40:43 +00:00
|
|
|
StatePropertyIsDeprecated (bag.Info->Class->TypeName.GetChars(), "Melee");
|
2006-10-31 14:53:21 +00:00
|
|
|
AddState("Melee", CheckState ( bag.Info->Class));
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
static void ActorMissileState (AActor *defaults, Baggage &bag)
|
|
|
|
{
|
2006-05-10 02:40:43 +00:00
|
|
|
StatePropertyIsDeprecated (bag.Info->Class->TypeName.GetChars(), "Missile");
|
2006-10-31 14:53:21 +00:00
|
|
|
AddState("Missile", CheckState ( bag.Info->Class));
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
static void ActorPainState (AActor *defaults, Baggage &bag)
|
|
|
|
{
|
2006-05-10 02:40:43 +00:00
|
|
|
StatePropertyIsDeprecated (bag.Info->Class->TypeName.GetChars(), "Pain");
|
2006-10-31 14:53:21 +00:00
|
|
|
AddState("Pain", CheckState ( bag.Info->Class));
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
static void ActorDeathState (AActor *defaults, Baggage &bag)
|
|
|
|
{
|
2006-05-10 02:40:43 +00:00
|
|
|
StatePropertyIsDeprecated (bag.Info->Class->TypeName.GetChars(), "Death");
|
2006-10-31 14:53:21 +00:00
|
|
|
AddState("Death", CheckState ( bag.Info->Class));
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
static void ActorXDeathState (AActor *defaults, Baggage &bag)
|
|
|
|
{
|
2006-05-10 02:40:43 +00:00
|
|
|
StatePropertyIsDeprecated (bag.Info->Class->TypeName.GetChars(), "XDeath");
|
2006-10-31 14:53:21 +00:00
|
|
|
AddState("XDeath", CheckState ( bag.Info->Class));
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
static void ActorBurnState (AActor *defaults, Baggage &bag)
|
|
|
|
{
|
2006-05-10 02:40:43 +00:00
|
|
|
StatePropertyIsDeprecated (bag.Info->Class->TypeName.GetChars(), "Burn");
|
2006-10-31 14:53:21 +00:00
|
|
|
AddState("Burn", CheckState ( bag.Info->Class));
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
static void ActorIceState (AActor *defaults, Baggage &bag)
|
|
|
|
{
|
2006-05-10 02:40:43 +00:00
|
|
|
StatePropertyIsDeprecated (bag.Info->Class->TypeName.GetChars(), "Ice");
|
2006-10-31 14:53:21 +00:00
|
|
|
AddState("Ice", CheckState ( bag.Info->Class));
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
static void ActorRaiseState (AActor *defaults, Baggage &bag)
|
|
|
|
{
|
2006-05-10 02:40:43 +00:00
|
|
|
StatePropertyIsDeprecated (bag.Info->Class->TypeName.GetChars(), "Raise");
|
2006-10-31 14:53:21 +00:00
|
|
|
AddState("Raise", CheckState ( bag.Info->Class));
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
static void ActorCrashState (AActor *defaults, Baggage &bag)
|
|
|
|
{
|
2006-05-10 02:40:43 +00:00
|
|
|
StatePropertyIsDeprecated (bag.Info->Class->TypeName.GetChars(), "Crash");
|
2006-10-31 14:53:21 +00:00
|
|
|
AddState("Crash", CheckState ( bag.Info->Class));
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
static void ActorCrushState (AActor *defaults, Baggage &bag)
|
|
|
|
{
|
2006-05-10 02:40:43 +00:00
|
|
|
StatePropertyIsDeprecated (bag.Info->Class->TypeName.GetChars(), "Crush");
|
2006-10-31 14:53:21 +00:00
|
|
|
AddState("Crush", CheckState ( bag.Info->Class));
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
static void ActorWoundState (AActor *defaults, Baggage &bag)
|
|
|
|
{
|
2006-05-10 02:40:43 +00:00
|
|
|
StatePropertyIsDeprecated (bag.Info->Class->TypeName.GetChars(), "Wound");
|
2006-10-31 14:53:21 +00:00
|
|
|
AddState("Wound", CheckState ( bag.Info->Class));
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
static void ActorDisintegrateState (AActor *defaults, Baggage &bag)
|
|
|
|
{
|
2006-05-10 02:40:43 +00:00
|
|
|
StatePropertyIsDeprecated (bag.Info->Class->TypeName.GetChars(), "Disintegrate");
|
2006-10-31 14:53:21 +00:00
|
|
|
AddState("Disintegrate", CheckState ( bag.Info->Class));
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
static void ActorHealState (AActor *defaults, Baggage &bag)
|
|
|
|
{
|
2006-05-10 02:40:43 +00:00
|
|
|
StatePropertyIsDeprecated (bag.Info->Class->TypeName.GetChars(), "Heal");
|
2006-10-31 14:53:21 +00:00
|
|
|
AddState("Heal", CheckState ( bag.Info->Class));
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
static void ActorStates (AActor *defaults, Baggage &bag)
|
|
|
|
{
|
|
|
|
if (!bag.StateSet) ProcessStates(bag.Info, defaults, bag);
|
|
|
|
else SC_ScriptError("Multiple state declarations not allowed");
|
|
|
|
bag.StateSet=true;
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
static void ActorRenderStyle (AActor *defaults, Baggage &bag)
|
|
|
|
{
|
|
|
|
static const char * renderstyles[]={
|
|
|
|
"NONE","NORMAL","FUZZY","SOULTRANS","OPTFUZZY","STENCIL","TRANSLUCENT", "ADD",NULL};
|
|
|
|
|
|
|
|
static const int renderstyle_values[]={
|
|
|
|
STYLE_None, STYLE_Normal, STYLE_Fuzzy, STYLE_SoulTrans, STYLE_OptFuzzy,
|
|
|
|
STYLE_Stencil, STYLE_Translucent, STYLE_Add};
|
|
|
|
|
|
|
|
SC_MustGetString();
|
|
|
|
defaults->RenderStyle=renderstyle_values[SC_MustMatchString(renderstyles)];
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
static void ActorAlpha (AActor *defaults, Baggage &bag)
|
|
|
|
{
|
2006-05-03 14:54:48 +00:00
|
|
|
if (SC_CheckString("DEFAULT"))
|
|
|
|
{
|
|
|
|
defaults->alpha = gameinfo.gametype==GAME_Heretic? HR_SHADOW : HX_SHADOW;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
SC_MustGetFloat();
|
|
|
|
defaults->alpha=fixed_t(sc_Float*FRACUNIT);
|
|
|
|
}
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
static void ActorObituary (AActor *defaults, Baggage &bag)
|
|
|
|
{
|
|
|
|
SC_MustGetString();
|
|
|
|
bag.Info->Class->Meta.SetMetaString (AMETA_Obituary, sc_String);
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
static void ActorHitObituary (AActor *defaults, Baggage &bag)
|
|
|
|
{
|
|
|
|
SC_MustGetString();
|
|
|
|
bag.Info->Class->Meta.SetMetaString (AMETA_HitObituary, sc_String);
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
static void ActorDontHurtShooter (AActor *defaults, Baggage &bag)
|
|
|
|
{
|
2006-07-29 10:47:14 +00:00
|
|
|
bag.Info->Class->Meta.SetMetaInt (ACMETA_DontHurtShooter, true);
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
static void ActorExplosionRadius (AActor *defaults, Baggage &bag)
|
|
|
|
{
|
|
|
|
SC_MustGetNumber();
|
2006-07-29 10:47:14 +00:00
|
|
|
bag.Info->Class->Meta.SetMetaInt (ACMETA_ExplosionRadius, sc_Number);
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
static void ActorExplosionDamage (AActor *defaults, Baggage &bag)
|
|
|
|
{
|
|
|
|
SC_MustGetNumber();
|
2006-07-29 10:47:14 +00:00
|
|
|
bag.Info->Class->Meta.SetMetaInt (ACMETA_ExplosionDamage, sc_Number);
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
static void ActorDeathHeight (AActor *defaults, Baggage &bag)
|
|
|
|
{
|
|
|
|
SC_MustGetFloat();
|
|
|
|
fixed_t h = fixed_t(sc_Float * FRACUNIT);
|
|
|
|
// AActor::Die() uses a height of 0 to mean "cut the height to 1/4",
|
|
|
|
// so if a height of 0 is desired, store it as -1.
|
|
|
|
bag.Info->Class->Meta.SetMetaFixed (AMETA_DeathHeight, h <= 0 ? -1 : h);
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
static void ActorBurnHeight (AActor *defaults, Baggage &bag)
|
|
|
|
{
|
|
|
|
SC_MustGetFloat();
|
|
|
|
fixed_t h = fixed_t(sc_Float * FRACUNIT);
|
|
|
|
// The note above for AMETA_DeathHeight also applies here.
|
|
|
|
bag.Info->Class->Meta.SetMetaFixed (AMETA_BurnHeight, h <= 0 ? -1 : h);
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
static void ActorMeleeDamage (AActor *defaults, Baggage &bag)
|
|
|
|
{
|
|
|
|
SC_MustGetNumber();
|
|
|
|
bag.BAttack.MeleeDamage = sc_Number;
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
static void ActorMeleeRange (AActor *defaults, Baggage &bag)
|
|
|
|
{
|
2006-07-13 10:17:56 +00:00
|
|
|
SC_MustGetFloat();
|
|
|
|
defaults->meleerange = fixed_t(sc_Float*FRACUNIT);
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
static void ActorMeleeSound (AActor *defaults, Baggage &bag)
|
|
|
|
{
|
|
|
|
SC_MustGetString();
|
|
|
|
bag.BAttack.MeleeSound = S_FindSound(sc_String);
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
static void ActorMissileType (AActor *defaults, Baggage &bag)
|
|
|
|
{
|
|
|
|
SC_MustGetString();
|
2006-05-09 03:40:15 +00:00
|
|
|
bag.BAttack.MissileName = sc_String;
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
static void ActorMissileHeight (AActor *defaults, Baggage &bag)
|
|
|
|
{
|
|
|
|
SC_MustGetFloat();
|
|
|
|
bag.BAttack.MissileHeight = fixed_t(sc_Float*FRACUNIT);
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
static void ActorTranslation (AActor *defaults, Baggage &bag)
|
|
|
|
{
|
|
|
|
if (SC_CheckNumber())
|
|
|
|
{
|
2006-05-07 00:27:22 +00:00
|
|
|
int max = (gameinfo.gametype==GAME_Strife || (bag.Info->GameFilter&GAME_Strife)) ? 6:2;
|
2006-02-24 04:48:15 +00:00
|
|
|
if (sc_Number < 0 || sc_Number > max)
|
|
|
|
{
|
|
|
|
SC_ScriptError ("Translation must be in the range [0,%d]", max);
|
|
|
|
}
|
|
|
|
defaults->Translation = TRANSLATION(TRANSLATION_Standard, sc_Number);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
unsigned char translation[256];
|
|
|
|
for(int i=0;i<256;i++) translation[i]=i;
|
|
|
|
do
|
|
|
|
{
|
|
|
|
SC_GetString();
|
|
|
|
AddToTranslation(translation,sc_String);
|
|
|
|
}
|
|
|
|
while (SC_CheckString(","));
|
|
|
|
defaults->Translation = StoreTranslation (translation);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
static void ActorBloodColor (AActor *defaults, Baggage &bag)
|
|
|
|
{
|
|
|
|
int r,g,b;
|
|
|
|
|
|
|
|
if (SC_CheckNumber())
|
|
|
|
{
|
|
|
|
SC_MustGetNumber();
|
|
|
|
r=clamp<int>(sc_Number, 0, 255);
|
2006-07-31 10:22:53 +00:00
|
|
|
SC_CheckString(",");
|
2006-02-24 04:48:15 +00:00
|
|
|
SC_MustGetNumber();
|
|
|
|
g=clamp<int>(sc_Number, 0, 255);
|
2006-07-31 10:22:53 +00:00
|
|
|
SC_CheckString(",");
|
2006-02-24 04:48:15 +00:00
|
|
|
SC_MustGetNumber();
|
|
|
|
b=clamp<int>(sc_Number, 0, 255);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
SC_MustGetString();
|
|
|
|
int c = V_GetColor(NULL, sc_String);
|
|
|
|
r=RPART(c);
|
|
|
|
g=GPART(c);
|
|
|
|
b=BPART(c);
|
|
|
|
}
|
|
|
|
PalEntry pe = MAKERGB(r,g,b);
|
|
|
|
pe.a = CreateBloodTranslation(pe);
|
|
|
|
bag.Info->Class->Meta.SetMetaInt (AMETA_BloodColor, pe);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2006-11-29 10:03:35 +00:00
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
static void ActorBloodType (AActor *defaults, Baggage &bag)
|
|
|
|
{
|
|
|
|
SC_MustGetString();
|
|
|
|
FName blood = sc_String;
|
|
|
|
// normal blood
|
|
|
|
bag.Info->Class->Meta.SetMetaInt (AMETA_BloodType, blood);
|
|
|
|
|
|
|
|
if (SC_CheckString(","))
|
|
|
|
{
|
|
|
|
SC_MustGetString();
|
|
|
|
blood = sc_String;
|
|
|
|
}
|
|
|
|
// blood splatter
|
|
|
|
bag.Info->Class->Meta.SetMetaInt (AMETA_BloodType2, blood);
|
|
|
|
|
|
|
|
if (SC_CheckString(","))
|
|
|
|
{
|
|
|
|
SC_MustGetString();
|
|
|
|
blood = sc_String;
|
|
|
|
}
|
|
|
|
// axe blood
|
|
|
|
bag.Info->Class->Meta.SetMetaInt (AMETA_BloodType3, blood);
|
|
|
|
}
|
|
|
|
|
2006-04-11 16:27:41 +00:00
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
static void ActorBounceFactor (AActor *defaults, Baggage &bag)
|
|
|
|
{
|
|
|
|
SC_MustGetFloat ();
|
2006-04-18 22:15:05 +00:00
|
|
|
defaults->bouncefactor = clamp<fixed_t>(fixed_t(sc_Float * FRACUNIT), 0, FRACUNIT);
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
static void ActorBounceCount (AActor *defaults, Baggage &bag)
|
|
|
|
{
|
|
|
|
SC_MustGetNumber ();
|
|
|
|
defaults->bouncecount = sc_Number;
|
2006-04-11 16:27:41 +00:00
|
|
|
}
|
|
|
|
|
2006-02-24 04:48:15 +00:00
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
static void ActorMinMissileChance (AActor *defaults, Baggage &bag)
|
|
|
|
{
|
|
|
|
SC_MustGetNumber ();
|
|
|
|
defaults->MinMissileChance=sc_Number;
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
static void ActorDamageType (AActor *defaults, Baggage &bag)
|
|
|
|
{
|
|
|
|
SC_MustGetString ();
|
2006-10-31 14:53:21 +00:00
|
|
|
if (SC_Compare("Normal")) defaults->DamageType = NAME_None;
|
|
|
|
else defaults->DamageType=sc_String;
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
static void ActorDecal (AActor *defaults, Baggage &bag)
|
|
|
|
{
|
|
|
|
SC_MustGetString();
|
|
|
|
defaults->DecalGenerator = (FDecalBase *) ((size_t)DecalNames.Push(copystring(sc_String))+1);
|
|
|
|
}
|
|
|
|
|
2006-04-11 08:36:23 +00:00
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
static void ActorMaxStepHeight (AActor *defaults, Baggage &bag)
|
|
|
|
{
|
|
|
|
SC_MustGetNumber ();
|
2006-07-08 20:17:52 +00:00
|
|
|
defaults->MaxStepHeight=sc_Number * FRACUNIT;
|
2006-04-11 08:36:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
static void ActorMaxDropoffHeight (AActor *defaults, Baggage &bag)
|
|
|
|
{
|
|
|
|
SC_MustGetNumber ();
|
2006-07-08 20:17:52 +00:00
|
|
|
defaults->MaxDropOffHeight=sc_Number * FRACUNIT;
|
2006-04-11 08:36:23 +00:00
|
|
|
}
|
|
|
|
|
2006-05-07 00:27:22 +00:00
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
static void ActorPoisonDamage (AActor *defaults, Baggage &bag)
|
|
|
|
{
|
|
|
|
SC_MustGetNumber();
|
|
|
|
bag.Info->Class->Meta.SetMetaInt (AMETA_PoisonDamage, sc_Number);
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
static void ActorFastSpeed (AActor *defaults, Baggage &bag)
|
|
|
|
{
|
|
|
|
SC_MustGetFloat();
|
|
|
|
bag.Info->Class->Meta.SetMetaFixed (AMETA_FastSpeed, fixed_t(sc_Float*FRACUNIT));
|
|
|
|
}
|
|
|
|
|
2006-06-03 12:30:11 +00:00
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
static void ActorRadiusDamageFactor (AActor *defaults, Baggage &bag)
|
|
|
|
{
|
|
|
|
SC_MustGetFloat();
|
|
|
|
bag.Info->Class->Meta.SetMetaFixed (AMETA_RDFactor, fixed_t(sc_Float*FRACUNIT));
|
|
|
|
}
|
|
|
|
|
2006-10-22 10:32:41 +00:00
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
static void ActorCameraheight (AActor *defaults, Baggage &bag)
|
|
|
|
{
|
|
|
|
SC_MustGetFloat();
|
|
|
|
bag.Info->Class->Meta.SetMetaFixed (AMETA_CameraHeight, fixed_t(sc_Float*FRACUNIT));
|
|
|
|
}
|
|
|
|
|
2006-11-04 13:06:42 +00:00
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
static void ActorVSpeed (AActor *defaults, Baggage &bag)
|
|
|
|
{
|
|
|
|
SC_MustGetFloat();
|
|
|
|
defaults->momz = fixed_t(sc_Float*FRACUNIT);
|
|
|
|
}
|
|
|
|
|
2006-02-24 04:48:15 +00:00
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
static void ActorClearFlags (AActor *defaults, Baggage &bag)
|
|
|
|
{
|
2006-12-02 15:38:50 +00:00
|
|
|
defaults->flags=defaults->flags3=defaults->flags4=defaults->flags5=0;
|
|
|
|
defaults->flags2&=MF2_ARGSDEFINED; // this flag must not be cleared
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
static void ActorMonster (AActor *defaults, Baggage &bag)
|
|
|
|
{
|
|
|
|
// sets the standard flag for a monster
|
|
|
|
defaults->flags|=MF_SHOOTABLE|MF_COUNTKILL|MF_SOLID;
|
|
|
|
defaults->flags2|=MF2_PUSHWALL|MF2_MCROSS|MF2_PASSMOBJ;
|
|
|
|
defaults->flags3|=MF3_ISMONSTER;
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
static void ActorProjectile (AActor *defaults, Baggage &bag)
|
|
|
|
{
|
|
|
|
// sets the standard flags for a projectile
|
|
|
|
defaults->flags|=MF_NOBLOCKMAP|MF_NOGRAVITY|MF_DROPOFF|MF_MISSILE;
|
|
|
|
defaults->flags2|=MF2_IMPACT|MF2_PCROSS|MF2_NOTELEPORT;
|
2006-05-13 12:41:15 +00:00
|
|
|
if (gameinfo.gametype&GAME_Raven) defaults->flags5|=MF5_BLOODSPLATTER;
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
static void ActorFlagSetOrReset (AActor *defaults, Baggage &bag)
|
|
|
|
{
|
|
|
|
char mod = sc_String[0];
|
|
|
|
flagdef *fd;
|
|
|
|
|
|
|
|
SC_MustGetString ();
|
|
|
|
|
|
|
|
// Fire and ice damage were once flags but now are not.
|
|
|
|
if (SC_Compare ("FIREDAMAGE"))
|
|
|
|
{
|
2006-10-31 14:53:21 +00:00
|
|
|
if (mod == '+') defaults->DamageType = NAME_Fire;
|
|
|
|
else defaults->DamageType = NAME_None;
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
else if (SC_Compare ("ICEDAMAGE"))
|
|
|
|
{
|
2006-10-31 14:53:21 +00:00
|
|
|
if (mod == '+') defaults->DamageType = NAME_Ice;
|
|
|
|
else defaults->DamageType = NAME_None;
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2006-05-03 22:45:01 +00:00
|
|
|
FString part1 = sc_String;
|
2006-02-24 04:48:15 +00:00
|
|
|
const char *part2 = NULL;
|
|
|
|
if (SC_CheckString ("."))
|
|
|
|
{
|
|
|
|
SC_MustGetString ();
|
|
|
|
part2 = sc_String;
|
|
|
|
}
|
2006-05-22 01:34:07 +00:00
|
|
|
if ( (fd = FindFlag (bag.Info->Class, part1.GetChars(), part2)) )
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
|
|
|
DWORD * flagvar = (DWORD*) ((char*)defaults + fd->structoffset);
|
|
|
|
if (mod == '+')
|
|
|
|
{
|
|
|
|
*flagvar |= fd->flagbit;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
*flagvar &= ~fd->flagbit;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (part2 == NULL)
|
|
|
|
{
|
|
|
|
SC_ScriptError("\"%s\" is an unknown flag\n", part1.GetChars());
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
SC_ScriptError("\"%s.%s\" is an unknown flag\n", part1.GetChars(), part2);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
// Special inventory properties
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
static void AmmoBackpackAmount (AAmmo *defaults, Baggage &bag)
|
|
|
|
{
|
|
|
|
SC_MustGetNumber();
|
|
|
|
defaults->BackpackAmount=sc_Number;
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
static void AmmoBackpackMaxAmount (AAmmo *defaults, Baggage &bag)
|
|
|
|
{
|
|
|
|
SC_MustGetNumber();
|
|
|
|
defaults->BackpackMaxAmount=sc_Number;
|
|
|
|
}
|
|
|
|
|
2006-05-28 14:54:01 +00:00
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
static void AmmoDropAmount (AAmmo *defaults, Baggage &bag)
|
|
|
|
{
|
|
|
|
SC_MustGetNumber();
|
|
|
|
bag.Info->Class->Meta.SetMetaInt (AIMETA_DropAmount, sc_Number);
|
|
|
|
}
|
|
|
|
|
2006-02-24 04:48:15 +00:00
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
static void ArmorMaxSaveAmount (ABasicArmorBonus *defaults, Baggage &bag)
|
|
|
|
{
|
|
|
|
SC_MustGetNumber();
|
|
|
|
defaults->MaxSaveAmount=sc_Number;
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
static void ArmorSaveAmount (AActor *defaults, Baggage &bag)
|
|
|
|
{
|
|
|
|
SC_MustGetNumber();
|
|
|
|
// Special case here because this property has to work for 2 unrelated classes
|
|
|
|
if (bag.Info->Class->IsDescendantOf(RUNTIME_CLASS(ABasicArmorPickup)))
|
|
|
|
{
|
|
|
|
((ABasicArmorPickup*)defaults)->SaveAmount=sc_Number;
|
|
|
|
}
|
|
|
|
else if (bag.Info->Class->IsDescendantOf(RUNTIME_CLASS(ABasicArmorBonus)))
|
|
|
|
{
|
|
|
|
((ABasicArmorBonus*)defaults)->SaveAmount=sc_Number;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
SC_ScriptError("\"%s\" requires an actor of type \"Armor\"\n", sc_String);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
static void ArmorSavePercent (AActor *defaults, Baggage &bag)
|
|
|
|
{
|
|
|
|
SC_MustGetFloat();
|
|
|
|
if (sc_Float<0.0f) sc_Float=0.0f;
|
|
|
|
if (sc_Float>100.0f) sc_Float=100.0f;
|
|
|
|
// Special case here because this property has to work for 2 unrelated classes
|
|
|
|
if (bag.Info->Class->IsDescendantOf(RUNTIME_CLASS(ABasicArmorPickup)))
|
|
|
|
{
|
2006-04-12 03:03:58 +00:00
|
|
|
((ABasicArmorPickup*)defaults)->SavePercent=fixed_t(sc_Float*FRACUNIT/100.0f);
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
else if (bag.Info->Class->IsDescendantOf(RUNTIME_CLASS(ABasicArmorBonus)))
|
|
|
|
{
|
2006-04-12 03:03:58 +00:00
|
|
|
((ABasicArmorBonus*)defaults)->SavePercent=fixed_t(sc_Float*FRACUNIT/100.0f);
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
SC_ScriptError("\"%s\" requires an actor of type \"Armor\"\n", sc_String);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
static void InventoryAmount (AInventory *defaults, Baggage &bag)
|
|
|
|
{
|
|
|
|
SC_MustGetNumber();
|
|
|
|
defaults->Amount=sc_Number;
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
static void InventoryIcon (AInventory *defaults, Baggage &bag)
|
|
|
|
{
|
|
|
|
SC_MustGetString();
|
|
|
|
defaults->Icon = TexMan.AddPatch (sc_String);
|
|
|
|
if (defaults->Icon <= 0)
|
|
|
|
{
|
|
|
|
defaults->Icon = TexMan.AddPatch (sc_String, ns_sprites);
|
|
|
|
if (defaults->Icon<=0)
|
|
|
|
{
|
2006-04-30 21:49:18 +00:00
|
|
|
if (bag.Info->GameFilter == GAME_Any || bag.Info->GameFilter & gameinfo.gametype)
|
2006-05-10 02:40:43 +00:00
|
|
|
Printf("Icon '%s' for '%s' not found\n", sc_String, bag.Info->Class->TypeName.GetChars());
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
static void InventoryMaxAmount (AInventory *defaults, Baggage &bag)
|
|
|
|
{
|
|
|
|
SC_MustGetNumber();
|
|
|
|
defaults->MaxAmount=sc_Number;
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
static void InventoryDefMaxAmount (AInventory *defaults, Baggage &bag)
|
|
|
|
{
|
|
|
|
defaults->MaxAmount = gameinfo.gametype == GAME_Heretic ? 16 : 25;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
static void InventoryPickupmsg (AInventory *defaults, Baggage &bag)
|
|
|
|
{
|
2006-05-03 14:54:48 +00:00
|
|
|
// allow game specific pickup messages
|
|
|
|
const char * games[] = {"Doom", "Heretic", "Hexen", "Raven", "Strife", NULL};
|
|
|
|
int gamemode[]={GAME_Doom, GAME_Heretic, GAME_Hexen, GAME_Raven, GAME_Strife};
|
|
|
|
|
2006-02-24 04:48:15 +00:00
|
|
|
SC_MustGetString();
|
2006-05-03 14:54:48 +00:00
|
|
|
int game = SC_MatchString(games);
|
|
|
|
|
2006-07-31 10:22:53 +00:00
|
|
|
if (game!=-1 && SC_CheckString(","))
|
2006-05-03 14:54:48 +00:00
|
|
|
{
|
|
|
|
SC_MustGetString();
|
|
|
|
if (!(gameinfo.gametype&gamemode[game])) return;
|
|
|
|
}
|
2006-02-24 04:48:15 +00:00
|
|
|
bag.Info->Class->Meta.SetMetaString(AIMETA_PickupMessage, sc_String);
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
static void InventoryPickupsound (AInventory *defaults, Baggage &bag)
|
|
|
|
{
|
|
|
|
SC_MustGetString();
|
|
|
|
defaults->PickupSound=S_FindSound(sc_String);
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
static void InventoryRespawntics (AInventory *defaults, Baggage &bag)
|
|
|
|
{
|
|
|
|
SC_MustGetNumber();
|
|
|
|
defaults->RespawnTics=sc_Number;
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
static void InventoryUsesound (AInventory *defaults, Baggage &bag)
|
|
|
|
{
|
|
|
|
SC_MustGetString();
|
|
|
|
defaults->UseSound=S_FindSound(sc_String);
|
|
|
|
}
|
|
|
|
|
2006-05-07 00:27:22 +00:00
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//==========================================================================
|
2006-08-18 22:22:39 +00:00
|
|
|
static void InventoryGiveQuest (AInventory *defaults, Baggage &bag)
|
2006-05-07 00:27:22 +00:00
|
|
|
{
|
|
|
|
SC_MustGetNumber();
|
|
|
|
bag.Info->Class->Meta.SetMetaInt(AIMETA_GiveQuest, sc_Number);
|
|
|
|
}
|
|
|
|
|
2006-06-17 20:29:41 +00:00
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
static void HealthLowMessage (AHealth *defaults, Baggage &bag)
|
|
|
|
{
|
|
|
|
SC_MustGetNumber();
|
|
|
|
bag.Info->Class->Meta.SetMetaInt(AIMETA_LowHealth, sc_Number);
|
|
|
|
SC_MustGetStringName(",");
|
|
|
|
SC_MustGetString();
|
|
|
|
bag.Info->Class->Meta.SetMetaString(AIMETA_LowHealthMessage, sc_String);
|
|
|
|
}
|
|
|
|
|
2006-02-24 04:48:15 +00:00
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
static void PuzzleitemNumber (APuzzleItem *defaults, Baggage &bag)
|
|
|
|
{
|
|
|
|
SC_MustGetNumber();
|
|
|
|
defaults->PuzzleItemNumber=sc_Number;
|
|
|
|
}
|
|
|
|
|
2006-08-18 22:22:39 +00:00
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
static void PuzzleitemFailMsg (APuzzleItem *defaults, Baggage &bag)
|
|
|
|
{
|
|
|
|
SC_MustGetString();
|
|
|
|
bag.Info->Class->Meta.SetMetaString(AIMETA_PuzzFailMessage, sc_String);
|
|
|
|
}
|
|
|
|
|
2006-02-24 04:48:15 +00:00
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
static void WeaponAmmoGive1 (AWeapon *defaults, Baggage &bag)
|
|
|
|
{
|
|
|
|
SC_MustGetNumber();
|
|
|
|
defaults->AmmoGive1=sc_Number;
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
static void WeaponAmmoGive2 (AWeapon *defaults, Baggage &bag)
|
|
|
|
{
|
|
|
|
SC_MustGetNumber();
|
|
|
|
defaults->AmmoGive2=sc_Number;
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
// Passing these parameters is really tricky to allow proper inheritance
|
2006-06-17 20:29:41 +00:00
|
|
|
// and forward declarations. Here only a name is
|
2006-02-24 04:48:15 +00:00
|
|
|
// stored which must be resolved after everything has been declared
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
static void WeaponAmmoType1 (AWeapon *defaults, Baggage &bag)
|
|
|
|
{
|
|
|
|
SC_MustGetString();
|
|
|
|
defaults->AmmoType1 = fuglyname(sc_String);
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
static void WeaponAmmoType2 (AWeapon *defaults, Baggage &bag)
|
|
|
|
{
|
|
|
|
SC_MustGetString();
|
|
|
|
defaults->AmmoType2 = fuglyname(sc_String);
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
static void WeaponAmmoUse1 (AWeapon *defaults, Baggage &bag)
|
|
|
|
{
|
|
|
|
SC_MustGetNumber();
|
|
|
|
defaults->AmmoUse1=sc_Number;
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
static void WeaponAmmoUse2 (AWeapon *defaults, Baggage &bag)
|
|
|
|
{
|
|
|
|
SC_MustGetNumber();
|
|
|
|
defaults->AmmoUse2=sc_Number;
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
static void WeaponKickback (AWeapon *defaults, Baggage &bag)
|
|
|
|
{
|
|
|
|
SC_MustGetNumber();
|
|
|
|
defaults->Kickback=sc_Number;
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
static void WeaponReadySound (AWeapon *defaults, Baggage &bag)
|
|
|
|
{
|
|
|
|
SC_MustGetString();
|
|
|
|
defaults->ReadySound=S_FindSound(sc_String);
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
static void WeaponSelectionOrder (AWeapon *defaults, Baggage &bag)
|
|
|
|
{
|
|
|
|
SC_MustGetNumber();
|
|
|
|
defaults->SelectionOrder=sc_Number;
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
static void WeaponSisterWeapon (AWeapon *defaults, Baggage &bag)
|
|
|
|
{
|
|
|
|
SC_MustGetString();
|
|
|
|
defaults->SisterWeaponType=fuglyname(sc_String);
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
static void WeaponUpSound (AWeapon *defaults, Baggage &bag)
|
|
|
|
{
|
|
|
|
SC_MustGetString();
|
|
|
|
defaults->UpSound=S_FindSound(sc_String);
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
static void WeaponYAdjust (AWeapon *defaults, Baggage &bag)
|
|
|
|
{
|
|
|
|
SC_MustGetFloat();
|
2006-04-12 03:03:58 +00:00
|
|
|
defaults->YAdjust=fixed_t(sc_Float * FRACUNIT);
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
static void WPieceValue (AWeaponPiece *defaults, Baggage &bag)
|
|
|
|
{
|
|
|
|
SC_MustGetNumber();
|
|
|
|
defaults->PieceValue = 1 << (sc_Number-1);
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
static void WPieceWeapon (AWeaponPiece *defaults, Baggage &bag)
|
|
|
|
{
|
|
|
|
SC_MustGetString();
|
|
|
|
defaults->WeaponClass = fuglyname(sc_String);
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
static void PowerupColor (APowerupGiver *defaults, Baggage &bag)
|
|
|
|
{
|
|
|
|
int r;
|
|
|
|
int g;
|
|
|
|
int b;
|
|
|
|
int alpha;
|
|
|
|
|
|
|
|
if (SC_CheckNumber())
|
|
|
|
{
|
|
|
|
r=clamp<int>(sc_Number, 0, 255);
|
2006-07-31 10:22:53 +00:00
|
|
|
SC_CheckString(",");
|
2006-02-24 04:48:15 +00:00
|
|
|
SC_MustGetNumber();
|
|
|
|
g=clamp<int>(sc_Number, 0, 255);
|
2006-07-31 10:22:53 +00:00
|
|
|
SC_CheckString(",");
|
2006-02-24 04:48:15 +00:00
|
|
|
SC_MustGetNumber();
|
|
|
|
b=clamp<int>(sc_Number, 0, 255);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
SC_MustGetString();
|
2006-05-03 14:54:48 +00:00
|
|
|
|
|
|
|
if (SC_Compare("INVERSEMAP"))
|
|
|
|
{
|
|
|
|
defaults->BlendColor = INVERSECOLOR;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
else if (SC_Compare("GOLDMAP"))
|
|
|
|
{
|
|
|
|
defaults->BlendColor = GOLDCOLOR;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2006-02-24 04:48:15 +00:00
|
|
|
int c = V_GetColor(NULL, sc_String);
|
|
|
|
r=RPART(c);
|
|
|
|
g=GPART(c);
|
|
|
|
b=BPART(c);
|
|
|
|
}
|
2006-07-31 10:22:53 +00:00
|
|
|
SC_CheckString(",");
|
2006-02-24 04:48:15 +00:00
|
|
|
SC_MustGetFloat();
|
2006-04-12 03:03:58 +00:00
|
|
|
alpha=int(sc_Float*255);
|
2006-02-24 04:48:15 +00:00
|
|
|
alpha=clamp<int>(alpha, 0, 255);
|
2006-05-03 14:54:48 +00:00
|
|
|
if (alpha!=0) defaults->BlendColor = MAKEARGB(alpha, r, g, b);
|
|
|
|
else defaults->BlendColor = 0;
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
static void PowerupDuration (APowerupGiver *defaults, Baggage &bag)
|
|
|
|
{
|
|
|
|
SC_MustGetNumber();
|
|
|
|
defaults->EffectTics = sc_Number;
|
|
|
|
}
|
|
|
|
|
2006-11-07 10:20:09 +00:00
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
static void PowerupMode (APowerupGiver *defaults, Baggage &bag)
|
|
|
|
{
|
|
|
|
SC_MustGetString();
|
|
|
|
defaults->mode = (FName)sc_String;
|
|
|
|
}
|
|
|
|
|
2006-02-24 04:48:15 +00:00
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
static void PowerupType (APowerupGiver *defaults, Baggage &bag)
|
|
|
|
{
|
2006-05-10 02:40:43 +00:00
|
|
|
FString typestr;
|
|
|
|
|
2006-02-24 04:48:15 +00:00
|
|
|
SC_MustGetString();
|
2006-05-10 02:40:43 +00:00
|
|
|
typestr.Format ("Power%s", sc_String);
|
|
|
|
const PClass * powertype=PClass::FindClass(typestr);
|
2006-02-24 04:48:15 +00:00
|
|
|
if (!powertype)
|
|
|
|
{
|
2006-05-10 02:40:43 +00:00
|
|
|
SC_ScriptError("Unknown powerup type '%s' in '%s'\n", sc_String, bag.Info->Class->TypeName.GetChars());
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
else if (!powertype->IsDescendantOf(RUNTIME_CLASS(APowerup)))
|
|
|
|
{
|
2006-05-10 02:40:43 +00:00
|
|
|
SC_ScriptError("Invalid powerup type '%s' in '%s'\n", sc_String, bag.Info->Class->TypeName.GetChars());
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
defaults->PowerupType=powertype;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-07-13 10:17:56 +00:00
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
// [GRB] Special player properties
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
static void PlayerDisplayName (APlayerPawn *defaults, Baggage &bag)
|
|
|
|
{
|
|
|
|
SC_MustGetString ();
|
|
|
|
bag.Info->Class->Meta.SetMetaString (APMETA_DisplayName, sc_String);
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
static void PlayerSoundClass (APlayerPawn *defaults, Baggage &bag)
|
|
|
|
{
|
2006-07-16 01:25:29 +00:00
|
|
|
FString tmp;
|
2006-07-13 10:17:56 +00:00
|
|
|
|
|
|
|
SC_MustGetString ();
|
2006-07-16 01:25:29 +00:00
|
|
|
tmp = sc_String;
|
|
|
|
tmp.ReplaceChars (' ', '_');
|
2006-07-13 10:17:56 +00:00
|
|
|
bag.Info->Class->Meta.SetMetaString (APMETA_SoundClass, tmp);
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
static void PlayerColorRange (APlayerPawn *defaults, Baggage &bag)
|
|
|
|
{
|
|
|
|
int start, end;
|
|
|
|
|
|
|
|
SC_MustGetNumber ();
|
|
|
|
start = sc_Number;
|
2006-07-31 10:22:53 +00:00
|
|
|
SC_CheckString(",");
|
2006-07-13 10:17:56 +00:00
|
|
|
SC_MustGetNumber ();
|
|
|
|
end = sc_Number;
|
|
|
|
|
|
|
|
if (start > end)
|
|
|
|
swap (start, end);
|
|
|
|
|
|
|
|
bag.Info->Class->Meta.SetMetaInt (APMETA_ColorRange, (start & 255) | ((end & 255) << 8));
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
static void PlayerJumpZ (APlayerPawn *defaults, Baggage &bag)
|
|
|
|
{
|
|
|
|
SC_MustGetFloat ();
|
|
|
|
defaults->JumpZ = FLOAT2FIXED (sc_Float);
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
static void PlayerSpawnClass (APlayerPawn *defaults, Baggage &bag)
|
|
|
|
{
|
|
|
|
SC_MustGetString ();
|
|
|
|
if (SC_Compare ("Any"))
|
|
|
|
defaults->SpawnMask = 0;
|
|
|
|
else if (SC_Compare ("Fighter"))
|
|
|
|
defaults->SpawnMask |= MTF_FIGHTER;
|
|
|
|
else if (SC_Compare ("Cleric"))
|
|
|
|
defaults->SpawnMask |= MTF_CLERIC;
|
|
|
|
else if (SC_Compare ("Mage"))
|
|
|
|
defaults->SpawnMask |= MTF_MAGE;
|
|
|
|
else if (IsNum(sc_String))
|
|
|
|
{
|
|
|
|
int val = strtol(sc_String, NULL, 0);
|
|
|
|
defaults->SpawnMask = (val*MTF_FIGHTER) & (MTF_FIGHTER|MTF_CLERIC|MTF_MAGE);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
static void PlayerViewHeight (APlayerPawn *defaults, Baggage &bag)
|
|
|
|
{
|
|
|
|
SC_MustGetFloat ();
|
|
|
|
defaults->ViewHeight = FLOAT2FIXED (sc_Float);
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
static void PlayerForwardMove (APlayerPawn *defaults, Baggage &bag)
|
|
|
|
{
|
|
|
|
SC_MustGetFloat ();
|
|
|
|
defaults->ForwardMove1 = defaults->ForwardMove2 = FLOAT2FIXED (sc_Float);
|
2006-07-31 10:22:53 +00:00
|
|
|
if (CheckFloatParm ())
|
2006-07-13 10:17:56 +00:00
|
|
|
defaults->ForwardMove2 = FLOAT2FIXED (sc_Float);
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
static void PlayerSideMove (APlayerPawn *defaults, Baggage &bag)
|
|
|
|
{
|
|
|
|
SC_MustGetFloat ();
|
|
|
|
defaults->SideMove1 = defaults->SideMove2 = FLOAT2FIXED (sc_Float);
|
2006-07-31 10:22:53 +00:00
|
|
|
if (CheckFloatParm ())
|
2006-07-13 10:17:56 +00:00
|
|
|
defaults->SideMove2 = FLOAT2FIXED (sc_Float);
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
static void PlayerMaxHealth (APlayerPawn *defaults, Baggage &bag)
|
|
|
|
{
|
|
|
|
SC_MustGetNumber ();
|
|
|
|
defaults->MaxHealth = sc_Number;
|
|
|
|
}
|
|
|
|
|
2006-08-17 00:19:26 +00:00
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
static void PlayerMorphWeapon (APlayerPawn *defaults, Baggage &bag)
|
|
|
|
{
|
|
|
|
SC_MustGetString ();
|
|
|
|
defaults->MorphWeapon = FName(sc_String);
|
|
|
|
}
|
|
|
|
|
2006-07-13 10:17:56 +00:00
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
static void PlayerScoreIcon (APlayerPawn *defaults, Baggage &bag)
|
|
|
|
{
|
|
|
|
SC_MustGetString ();
|
|
|
|
defaults->ScoreIcon = TexMan.AddPatch (sc_String);
|
|
|
|
if (defaults->ScoreIcon <= 0)
|
|
|
|
{
|
|
|
|
defaults->ScoreIcon = TexMan.AddPatch (sc_String, ns_sprites);
|
|
|
|
if (defaults->ScoreIcon <= 0)
|
|
|
|
{
|
|
|
|
Printf("Icon '%s' for '%s' not found\n", sc_String, bag.Info->Class->TypeName.GetChars ());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
static void PlayerCrouchSprite (APlayerPawn *defaults, Baggage &bag)
|
|
|
|
{
|
|
|
|
SC_MustGetString ();
|
2006-11-29 04:51:16 +00:00
|
|
|
for (unsigned int i = 0; i < sc_StringLen; i++) sc_String[i] = toupper (sc_String[i]);
|
2006-07-13 10:17:56 +00:00
|
|
|
defaults->crouchsprite = GetSpriteIndex (sc_String);
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
// [GRB] Store start items in drop item list
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
static void PlayerStartItem (APlayerPawn *defaults, Baggage &bag)
|
|
|
|
{
|
|
|
|
// create a linked list of dropitems
|
|
|
|
if (!bag.DropItemSet)
|
|
|
|
{
|
|
|
|
bag.DropItemSet = true;
|
|
|
|
bag.DropItemList = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
FDropItem * di=new FDropItem;
|
|
|
|
|
|
|
|
SC_MustGetString();
|
2006-07-16 09:10:45 +00:00
|
|
|
di->Name = sc_String;
|
2006-07-13 10:17:56 +00:00
|
|
|
di->probability=255;
|
|
|
|
di->amount=0;
|
2006-07-31 10:22:53 +00:00
|
|
|
if (CheckNumParm())
|
2006-07-13 10:17:56 +00:00
|
|
|
{
|
|
|
|
di->amount=sc_Number;
|
|
|
|
}
|
|
|
|
di->Next = bag.DropItemList;
|
|
|
|
bag.DropItemList = di;
|
|
|
|
}
|
|
|
|
|
2006-11-07 10:20:09 +00:00
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
static void PlayerInvulMode (APlayerPawn *defaults, Baggage &bag)
|
|
|
|
{
|
|
|
|
SC_MustGetString ();
|
|
|
|
bag.Info->Class->Meta.SetMetaInt (APMETA_InvulMode, (FName)sc_String);
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
static void PlayerHealRadius (APlayerPawn *defaults, Baggage &bag)
|
|
|
|
{
|
|
|
|
SC_MustGetString ();
|
|
|
|
bag.Info->Class->Meta.SetMetaInt (APMETA_HealingRadius, (FName)sc_String);
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
static void PlayerHexenArmor (APlayerPawn *defaults, Baggage &bag)
|
|
|
|
{
|
|
|
|
for (int i=0;i<5;i++)
|
|
|
|
{
|
|
|
|
SC_MustGetFloat ();
|
|
|
|
bag.Info->Class->Meta.SetMetaFixed (APMETA_Hexenarmor0+i, FLOAT2FIXED (sc_Float));
|
|
|
|
if (i!=4) SC_MustGetStringName(",");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-08-17 00:19:26 +00:00
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//==========================================================================
|
2006-08-17 09:54:42 +00:00
|
|
|
static void EggFXMonsterClass (AMorphProjectile *defaults, Baggage &bag)
|
2006-08-17 00:19:26 +00:00
|
|
|
{
|
|
|
|
SC_MustGetString ();
|
|
|
|
defaults->MonsterClass = FName(sc_String);
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//==========================================================================
|
2006-08-17 09:54:42 +00:00
|
|
|
static void EggFXPlayerClass (AMorphProjectile *defaults, Baggage &bag)
|
2006-08-17 00:19:26 +00:00
|
|
|
{
|
|
|
|
SC_MustGetString ();
|
|
|
|
defaults->PlayerClass = FName(sc_String);
|
|
|
|
}
|
|
|
|
|
2006-02-24 04:48:15 +00:00
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
static const ActorProps *APropSearch (const char *str, const ActorProps *props, int numprops)
|
|
|
|
{
|
|
|
|
int min = 0, max = numprops - 1;
|
|
|
|
|
|
|
|
while (min <= max)
|
|
|
|
{
|
|
|
|
int mid = (min + max) / 2;
|
|
|
|
int lexval = strcmp (str, props[mid].name);
|
|
|
|
if (lexval == 0)
|
|
|
|
{
|
|
|
|
return &props[mid];
|
|
|
|
}
|
|
|
|
else if (lexval > 0)
|
|
|
|
{
|
|
|
|
min = mid + 1;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
max = mid - 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
// all actor properties
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
#define apf ActorPropFunction
|
|
|
|
static const ActorProps props[] =
|
|
|
|
{
|
|
|
|
{ "+", ActorFlagSetOrReset, RUNTIME_CLASS(AActor) },
|
|
|
|
{ "-", ActorFlagSetOrReset, RUNTIME_CLASS(AActor) },
|
2006-11-29 04:51:16 +00:00
|
|
|
{ "action", ActorActionDef, RUNTIME_CLASS(AActor) },
|
2006-02-24 04:48:15 +00:00
|
|
|
{ "activesound", ActorActiveSound, RUNTIME_CLASS(AActor) },
|
|
|
|
{ "alpha", ActorAlpha, RUNTIME_CLASS(AActor) },
|
|
|
|
{ "ammo.backpackamount", (apf)AmmoBackpackAmount, RUNTIME_CLASS(AAmmo) },
|
|
|
|
{ "ammo.backpackmaxamount", (apf)AmmoBackpackMaxAmount, RUNTIME_CLASS(AAmmo) },
|
2006-05-28 14:54:01 +00:00
|
|
|
{ "ammo.dropamount", (apf)AmmoDropAmount, RUNTIME_CLASS(AAmmo) },
|
2006-12-02 15:38:50 +00:00
|
|
|
{ "args", ActorArgs, RUNTIME_CLASS(AActor) },
|
2006-02-24 04:48:15 +00:00
|
|
|
{ "armor.maxsaveamount", (apf)ArmorMaxSaveAmount, RUNTIME_CLASS(ABasicArmorBonus) },
|
|
|
|
{ "armor.saveamount", (apf)ArmorSaveAmount, RUNTIME_CLASS(AActor) },
|
|
|
|
{ "armor.savepercent", (apf)ArmorSavePercent, RUNTIME_CLASS(AActor) },
|
|
|
|
{ "attacksound", ActorAttackSound, RUNTIME_CLASS(AActor) },
|
|
|
|
{ "bloodcolor", ActorBloodColor, RUNTIME_CLASS(AActor) },
|
2006-11-29 10:03:35 +00:00
|
|
|
{ "bloodtype", ActorBloodType, RUNTIME_CLASS(AActor) },
|
2006-04-18 22:15:05 +00:00
|
|
|
{ "bouncecount", ActorBounceCount, RUNTIME_CLASS(AActor) },
|
2006-04-11 16:27:41 +00:00
|
|
|
{ "bouncefactor", ActorBounceFactor, RUNTIME_CLASS(AActor) },
|
2006-02-24 04:48:15 +00:00
|
|
|
{ "burn", ActorBurnState, RUNTIME_CLASS(AActor) },
|
|
|
|
{ "burnheight", ActorBurnHeight, RUNTIME_CLASS(AActor) },
|
2006-10-22 10:32:41 +00:00
|
|
|
{ "cameraheight", ActorCameraheight, RUNTIME_CLASS(AActor) },
|
2006-02-24 04:48:15 +00:00
|
|
|
{ "clearflags", ActorClearFlags, RUNTIME_CLASS(AActor) },
|
2006-11-29 04:51:16 +00:00
|
|
|
{ "const", ActorConstDef, RUNTIME_CLASS(AActor) },
|
2006-02-24 04:48:15 +00:00
|
|
|
{ "conversationid", ActorConversationID, RUNTIME_CLASS(AActor) },
|
|
|
|
{ "crash", ActorCrashState, RUNTIME_CLASS(AActor) },
|
|
|
|
{ "crush", ActorCrushState, RUNTIME_CLASS(AActor) },
|
|
|
|
{ "damage", ActorDamage, RUNTIME_CLASS(AActor) },
|
|
|
|
{ "damagetype", ActorDamageType, RUNTIME_CLASS(AActor) },
|
|
|
|
{ "death", ActorDeathState, RUNTIME_CLASS(AActor) },
|
|
|
|
{ "deathheight", ActorDeathHeight, RUNTIME_CLASS(AActor) },
|
|
|
|
{ "deathsound", ActorDeathSound, RUNTIME_CLASS(AActor) },
|
|
|
|
{ "decal", ActorDecal, RUNTIME_CLASS(AActor) },
|
|
|
|
{ "disintegrate", ActorDisintegrateState, RUNTIME_CLASS(AActor) },
|
|
|
|
{ "donthurtshooter", ActorDontHurtShooter, RUNTIME_CLASS(AActor) },
|
|
|
|
{ "dropitem", ActorDropItem, RUNTIME_CLASS(AActor) },
|
|
|
|
{ "explosiondamage", ActorExplosionDamage, RUNTIME_CLASS(AActor) },
|
|
|
|
{ "explosionradius", ActorExplosionRadius, RUNTIME_CLASS(AActor) },
|
2006-05-07 00:27:22 +00:00
|
|
|
{ "fastspeed", ActorFastSpeed, RUNTIME_CLASS(AActor) },
|
2006-05-14 14:30:13 +00:00
|
|
|
{ "floatspeed", ActorFloatSpeed, RUNTIME_CLASS(AActor) },
|
2006-04-30 21:49:18 +00:00
|
|
|
{ "game", ActorGame, RUNTIME_CLASS(AActor) },
|
2006-02-24 04:48:15 +00:00
|
|
|
{ "gibhealth", ActorGibHealth, RUNTIME_CLASS(AActor) },
|
|
|
|
{ "heal", ActorHealState, RUNTIME_CLASS(AActor) },
|
|
|
|
{ "health", ActorHealth, RUNTIME_CLASS(AActor) },
|
2006-06-17 20:29:41 +00:00
|
|
|
{ "health.lowmessage", (apf)HealthLowMessage, RUNTIME_CLASS(AHealth) },
|
2006-02-24 04:48:15 +00:00
|
|
|
{ "height", ActorHeight, RUNTIME_CLASS(AActor) },
|
|
|
|
{ "hitobituary", ActorHitObituary, RUNTIME_CLASS(AActor) },
|
2006-11-27 00:01:30 +00:00
|
|
|
{ "howlsound", ActorHowlSound, RUNTIME_CLASS(AActor) },
|
2006-02-24 04:48:15 +00:00
|
|
|
{ "ice", ActorIceState, RUNTIME_CLASS(AActor) },
|
|
|
|
{ "inventory.amount", (apf)InventoryAmount, RUNTIME_CLASS(AInventory) },
|
|
|
|
{ "inventory.defmaxamount", (apf)InventoryDefMaxAmount, RUNTIME_CLASS(AInventory) },
|
2006-05-07 00:27:22 +00:00
|
|
|
{ "inventory.givequest", (apf)InventoryGiveQuest, RUNTIME_CLASS(AInventory) },
|
2006-02-24 04:48:15 +00:00
|
|
|
{ "inventory.icon", (apf)InventoryIcon, RUNTIME_CLASS(AInventory) },
|
|
|
|
{ "inventory.maxamount", (apf)InventoryMaxAmount, RUNTIME_CLASS(AInventory) },
|
|
|
|
{ "inventory.pickupmessage", (apf)InventoryPickupmsg, RUNTIME_CLASS(AInventory) },
|
|
|
|
{ "inventory.pickupsound", (apf)InventoryPickupsound, RUNTIME_CLASS(AInventory) },
|
|
|
|
{ "inventory.respawntics", (apf)InventoryRespawntics, RUNTIME_CLASS(AInventory) },
|
|
|
|
{ "inventory.usesound", (apf)InventoryUsesound, RUNTIME_CLASS(AInventory) },
|
|
|
|
{ "mass", ActorMass, RUNTIME_CLASS(AActor) },
|
2006-04-11 08:36:23 +00:00
|
|
|
{ "maxdropoffheight", ActorMaxDropoffHeight, RUNTIME_CLASS(AActor) },
|
|
|
|
{ "maxstepheight", ActorMaxStepHeight, RUNTIME_CLASS(AActor) },
|
2006-02-24 04:48:15 +00:00
|
|
|
{ "melee", ActorMeleeState, RUNTIME_CLASS(AActor) },
|
|
|
|
{ "meleedamage", ActorMeleeDamage, RUNTIME_CLASS(AActor) },
|
|
|
|
{ "meleerange", ActorMeleeRange, RUNTIME_CLASS(AActor) },
|
|
|
|
{ "meleesound", ActorMeleeSound, RUNTIME_CLASS(AActor) },
|
|
|
|
{ "minmissilechance", ActorMinMissileChance, RUNTIME_CLASS(AActor) },
|
|
|
|
{ "missile", ActorMissileState, RUNTIME_CLASS(AActor) },
|
|
|
|
{ "missileheight", ActorMissileHeight, RUNTIME_CLASS(AActor) },
|
|
|
|
{ "missiletype", ActorMissileType, RUNTIME_CLASS(AActor) },
|
|
|
|
{ "monster", ActorMonster, RUNTIME_CLASS(AActor) },
|
2006-08-17 09:54:42 +00:00
|
|
|
{ "morphprojectile.monsterclass",(apf)EggFXMonsterClass, RUNTIME_CLASS(AMorphProjectile) },
|
|
|
|
{ "morphprojectile.playerclass",(apf)EggFXPlayerClass, RUNTIME_CLASS(AMorphProjectile) },
|
2006-02-24 04:48:15 +00:00
|
|
|
{ "obituary", ActorObituary, RUNTIME_CLASS(AActor) },
|
|
|
|
{ "pain", ActorPainState, RUNTIME_CLASS(AActor) },
|
|
|
|
{ "painchance", ActorPainChance, RUNTIME_CLASS(AActor) },
|
|
|
|
{ "painsound", ActorPainSound, RUNTIME_CLASS(AActor) },
|
2006-07-13 10:17:56 +00:00
|
|
|
{ "player.colorrange", (apf)PlayerColorRange, RUNTIME_CLASS(APlayerPawn) },
|
|
|
|
{ "player.crouchsprite", (apf)PlayerCrouchSprite, RUNTIME_CLASS(APlayerPawn) },
|
|
|
|
{ "player.displayname", (apf)PlayerDisplayName, RUNTIME_CLASS(APlayerPawn) },
|
|
|
|
{ "player.forwardmove", (apf)PlayerForwardMove, RUNTIME_CLASS(APlayerPawn) },
|
2006-11-07 10:20:09 +00:00
|
|
|
{ "player.healradiustype", (apf)PlayerHealRadius, RUNTIME_CLASS(APlayerPawn) },
|
|
|
|
{ "player.hexenarmor", (apf)PlayerHexenArmor, RUNTIME_CLASS(APlayerPawn) },
|
|
|
|
{ "player.invulnerabilitymode", (apf)PlayerInvulMode, RUNTIME_CLASS(APlayerPawn) },
|
2006-07-13 10:17:56 +00:00
|
|
|
{ "player.jumpz", (apf)PlayerJumpZ, RUNTIME_CLASS(APlayerPawn) },
|
|
|
|
{ "player.maxhealth", (apf)PlayerMaxHealth, RUNTIME_CLASS(APlayerPawn) },
|
2006-08-17 00:19:26 +00:00
|
|
|
{ "player.morphweapon", (apf)PlayerMorphWeapon, RUNTIME_CLASS(APlayerPawn) },
|
2006-07-13 10:17:56 +00:00
|
|
|
{ "player.scoreicon", (apf)PlayerScoreIcon, RUNTIME_CLASS(APlayerPawn) },
|
|
|
|
{ "player.sidemove", (apf)PlayerSideMove, RUNTIME_CLASS(APlayerPawn) },
|
|
|
|
{ "player.soundclass", (apf)PlayerSoundClass, RUNTIME_CLASS(APlayerPawn) },
|
|
|
|
{ "player.spawnclass", (apf)PlayerSpawnClass, RUNTIME_CLASS(APlayerPawn) },
|
|
|
|
{ "player.startitem", (apf)PlayerStartItem, RUNTIME_CLASS(APlayerPawn) },
|
|
|
|
{ "player.viewheight", (apf)PlayerViewHeight, RUNTIME_CLASS(APlayerPawn) },
|
2006-05-07 00:27:22 +00:00
|
|
|
{ "poisondamage", ActorPoisonDamage, RUNTIME_CLASS(AActor) },
|
2006-02-24 04:48:15 +00:00
|
|
|
{ "powerup.color", (apf)PowerupColor, RUNTIME_CLASS(APowerupGiver) },
|
|
|
|
{ "powerup.duration", (apf)PowerupDuration, RUNTIME_CLASS(APowerupGiver) },
|
2006-11-07 10:20:09 +00:00
|
|
|
{ "powerup.mode", (apf)PowerupMode, RUNTIME_CLASS(APowerupGiver) },
|
2006-02-24 04:48:15 +00:00
|
|
|
{ "powerup.type", (apf)PowerupType, RUNTIME_CLASS(APowerupGiver) },
|
|
|
|
{ "projectile", ActorProjectile, RUNTIME_CLASS(AActor) },
|
2006-08-18 22:22:39 +00:00
|
|
|
{ "puzzleitem.failmessage", (apf)PuzzleitemFailMsg, RUNTIME_CLASS(APuzzleItem) },
|
2006-02-24 04:48:15 +00:00
|
|
|
{ "puzzleitem.number", (apf)PuzzleitemNumber, RUNTIME_CLASS(APuzzleItem) },
|
|
|
|
{ "radius", ActorRadius, RUNTIME_CLASS(AActor) },
|
2006-06-03 12:30:11 +00:00
|
|
|
{ "radiusdamagefactor", ActorRadiusDamageFactor, RUNTIME_CLASS(AActor) },
|
2006-02-24 04:48:15 +00:00
|
|
|
{ "raise", ActorRaiseState, RUNTIME_CLASS(AActor) },
|
|
|
|
{ "reactiontime", ActorReactionTime, RUNTIME_CLASS(AActor) },
|
|
|
|
{ "renderstyle", ActorRenderStyle, RUNTIME_CLASS(AActor) },
|
|
|
|
{ "scale", ActorScale, RUNTIME_CLASS(AActor) },
|
|
|
|
{ "see", ActorSeeState, RUNTIME_CLASS(AActor) },
|
|
|
|
{ "seesound", ActorSeeSound, RUNTIME_CLASS(AActor) },
|
|
|
|
{ "skip_super", ActorSkipSuper, RUNTIME_CLASS(AActor) },
|
|
|
|
{ "spawn", ActorSpawnState, RUNTIME_CLASS(AActor) },
|
|
|
|
{ "spawnid", ActorSpawnID, RUNTIME_CLASS(AActor) },
|
|
|
|
{ "speed", ActorSpeed, RUNTIME_CLASS(AActor) },
|
|
|
|
{ "states", ActorStates, RUNTIME_CLASS(AActor) },
|
2006-05-07 00:27:22 +00:00
|
|
|
{ "tag", ActorTag, RUNTIME_CLASS(AActor) },
|
2006-02-24 04:48:15 +00:00
|
|
|
{ "translation", ActorTranslation, RUNTIME_CLASS(AActor) },
|
2006-11-04 13:06:42 +00:00
|
|
|
{ "vspeed", ActorVSpeed, RUNTIME_CLASS(AActor) },
|
2006-02-24 04:48:15 +00:00
|
|
|
{ "weapon.ammogive", (apf)WeaponAmmoGive1, RUNTIME_CLASS(AWeapon) },
|
|
|
|
{ "weapon.ammogive1", (apf)WeaponAmmoGive1, RUNTIME_CLASS(AWeapon) },
|
|
|
|
{ "weapon.ammogive2", (apf)WeaponAmmoGive2, RUNTIME_CLASS(AWeapon) },
|
|
|
|
{ "weapon.ammotype", (apf)WeaponAmmoType1, RUNTIME_CLASS(AWeapon) },
|
|
|
|
{ "weapon.ammotype1", (apf)WeaponAmmoType1, RUNTIME_CLASS(AWeapon) },
|
|
|
|
{ "weapon.ammotype2", (apf)WeaponAmmoType2, RUNTIME_CLASS(AWeapon) },
|
|
|
|
{ "weapon.ammouse", (apf)WeaponAmmoUse1, RUNTIME_CLASS(AWeapon) },
|
|
|
|
{ "weapon.ammouse1", (apf)WeaponAmmoUse1, RUNTIME_CLASS(AWeapon) },
|
|
|
|
{ "weapon.ammouse2", (apf)WeaponAmmoUse2, RUNTIME_CLASS(AWeapon) },
|
|
|
|
{ "weapon.kickback", (apf)WeaponKickback, RUNTIME_CLASS(AWeapon) },
|
|
|
|
{ "weapon.readysound", (apf)WeaponReadySound, RUNTIME_CLASS(AWeapon) },
|
|
|
|
{ "weapon.selectionorder", (apf)WeaponSelectionOrder, RUNTIME_CLASS(AWeapon) },
|
|
|
|
{ "weapon.sisterweapon", (apf)WeaponSisterWeapon, RUNTIME_CLASS(AWeapon) },
|
|
|
|
{ "weapon.upsound", (apf)WeaponUpSound, RUNTIME_CLASS(AWeapon) },
|
|
|
|
{ "weapon.yadjust", (apf)WeaponYAdjust, RUNTIME_CLASS(AWeapon) },
|
|
|
|
{ "weaponpiece.number", (apf)WPieceValue, RUNTIME_CLASS(AWeaponPiece) },
|
|
|
|
{ "weaponpiece.weapon", (apf)WPieceWeapon, RUNTIME_CLASS(AWeaponPiece) },
|
|
|
|
{ "wound", ActorWoundState, RUNTIME_CLASS(AActor) },
|
|
|
|
{ "woundhealth", ActorWoundHealth, RUNTIME_CLASS(AActor) },
|
|
|
|
{ "xdeath", ActorXDeathState, RUNTIME_CLASS(AActor) },
|
|
|
|
{ "xscale", ActorXScale, RUNTIME_CLASS(AActor) },
|
|
|
|
{ "yscale", ActorYScale, RUNTIME_CLASS(AActor) },
|
|
|
|
// AWeapon:MinAmmo1 and 2 are never used so there is no point in adding them here!
|
|
|
|
};
|
|
|
|
static const ActorProps *is_actorprop (const char *str)
|
|
|
|
{
|
|
|
|
return APropSearch (str, props, sizeof(props)/sizeof(ActorProps));
|
|
|
|
}
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
// Do some postprocessing after everything has been defined
|
2006-06-17 20:29:41 +00:00
|
|
|
// This also processes all the internal actors to adjust the type
|
|
|
|
// fields in the weapons
|
2006-02-24 04:48:15 +00:00
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
void FinishThingdef()
|
|
|
|
{
|
2006-04-13 02:01:40 +00:00
|
|
|
unsigned int i;
|
2006-06-17 20:29:41 +00:00
|
|
|
bool isRuntimeActor=false;
|
2006-02-24 04:48:15 +00:00
|
|
|
|
2006-06-17 20:29:41 +00:00
|
|
|
for (i = 0;i < PClass::m_Types.Size(); i++)
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
2006-06-17 20:29:41 +00:00
|
|
|
PClass * ti = PClass::m_Types[i];
|
|
|
|
|
|
|
|
// Skip non-actors
|
|
|
|
if (!ti->IsDescendantOf(RUNTIME_CLASS(AActor))) continue;
|
|
|
|
|
|
|
|
// Everything coming after the first runtime actor is also a runtime actor
|
|
|
|
// so this check is sufficient
|
|
|
|
if (ti == PClass::m_RuntimeActors[0])
|
|
|
|
{
|
|
|
|
isRuntimeActor=true;
|
|
|
|
}
|
2006-02-24 04:48:15 +00:00
|
|
|
|
|
|
|
// Friendlies never count as kills!
|
|
|
|
if (GetDefaultByType(ti)->flags & MF_FRIENDLY)
|
|
|
|
{
|
|
|
|
GetDefaultByType(ti)->flags &=~MF_COUNTKILL;
|
|
|
|
}
|
|
|
|
|
|
|
|
// the typeinfo properties of weapons have to be fixed here after all actors have been declared
|
|
|
|
if (ti->IsDescendantOf(RUNTIME_CLASS(AWeapon)))
|
|
|
|
{
|
2006-05-10 02:40:43 +00:00
|
|
|
AWeapon * defaults=(AWeapon *)ti->Defaults;
|
2006-02-24 04:48:15 +00:00
|
|
|
fuglyname v;
|
|
|
|
|
|
|
|
v = defaults->AmmoType1;
|
- Fixed: ActorFlagSetOrReset() wasn't receiving the + or - character from
ParseActorProperties().
- Fixed: The decorate FindFlag() function returned flags from ActorFlags
instead of the passed flags set.
- Fixed: The CHT_CHAINSAW, CHT_POWER, CHT_HEALTH, and CHT_RESSURECT needed
NULL player->mo checks.
- Fixed: The "give all" command didn't give the backpack in Doom, and it
must give the backpack before giving ammo.
- Fixed: P_SetPsprite() must not call the action function if the player is
not attached to an actor. This can happen, for instance, if the level is
destroyed while the player is holding a powered-up Phoenix Rod. As part
of its EndPowerup() function, it sets the psprite to the regular version,
but the player actor has already been destroyed.
- Fixed: FinishThingdef() needs to check for valid names, because weapons
could have inherited valid pointers from their superclass.
- Fixed: fuglyname didn't work.
- Fixed: Redefining $ambient sounds leaked memory.
- Added Jim's crashcatcher.c fix for better shell support.
- VC7.1 seems to have no trouble distinguishing between passing a (const
TypeInfo *) reference to operator<< and the generic, templated (object *)
version, so a few places that can benefit from it now use it. I believe
VC6 had problems with this, which is why I didn't do it all along. The
function's implementation was also moved out of dobject.cpp and into
farchive.cpp.
- Fixed: UnpackPixels() unpacked all chunks in a byte, which is wrong for the
last byte in a row if the image width is not an even multiple of the number
pixels per byte.
- Fixed: P_TranslateLineDef() should only clear monster activation for secret
useable lines, not crossable lines.
- Fixed: Some leftover P_IsHostile() calls still needed to be rewritten.
- Fixed: AWeaponHolder::Serialize() wrote the class type in all circumstances.
SVN r20 (trunk)
2006-03-14 06:11:39 +00:00
|
|
|
if (v != NAME_None && v.IsValidName())
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
2006-05-20 09:16:08 +00:00
|
|
|
defaults->AmmoType1 = PClass::FindClass(v);
|
2006-06-17 20:29:41 +00:00
|
|
|
if (isRuntimeActor)
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
2006-06-17 20:29:41 +00:00
|
|
|
if (!defaults->AmmoType1)
|
|
|
|
{
|
|
|
|
I_Error("Unknown ammo type '%s' in '%s'\n", v.GetChars(), ti->TypeName.GetChars());
|
|
|
|
}
|
|
|
|
else if (defaults->AmmoType1->ParentClass != RUNTIME_CLASS(AAmmo))
|
|
|
|
{
|
|
|
|
I_Error("Invalid ammo type '%s' in '%s'\n", v.GetChars(), ti->TypeName.GetChars());
|
|
|
|
}
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
v = defaults->AmmoType2;
|
- Fixed: ActorFlagSetOrReset() wasn't receiving the + or - character from
ParseActorProperties().
- Fixed: The decorate FindFlag() function returned flags from ActorFlags
instead of the passed flags set.
- Fixed: The CHT_CHAINSAW, CHT_POWER, CHT_HEALTH, and CHT_RESSURECT needed
NULL player->mo checks.
- Fixed: The "give all" command didn't give the backpack in Doom, and it
must give the backpack before giving ammo.
- Fixed: P_SetPsprite() must not call the action function if the player is
not attached to an actor. This can happen, for instance, if the level is
destroyed while the player is holding a powered-up Phoenix Rod. As part
of its EndPowerup() function, it sets the psprite to the regular version,
but the player actor has already been destroyed.
- Fixed: FinishThingdef() needs to check for valid names, because weapons
could have inherited valid pointers from their superclass.
- Fixed: fuglyname didn't work.
- Fixed: Redefining $ambient sounds leaked memory.
- Added Jim's crashcatcher.c fix for better shell support.
- VC7.1 seems to have no trouble distinguishing between passing a (const
TypeInfo *) reference to operator<< and the generic, templated (object *)
version, so a few places that can benefit from it now use it. I believe
VC6 had problems with this, which is why I didn't do it all along. The
function's implementation was also moved out of dobject.cpp and into
farchive.cpp.
- Fixed: UnpackPixels() unpacked all chunks in a byte, which is wrong for the
last byte in a row if the image width is not an even multiple of the number
pixels per byte.
- Fixed: P_TranslateLineDef() should only clear monster activation for secret
useable lines, not crossable lines.
- Fixed: Some leftover P_IsHostile() calls still needed to be rewritten.
- Fixed: AWeaponHolder::Serialize() wrote the class type in all circumstances.
SVN r20 (trunk)
2006-03-14 06:11:39 +00:00
|
|
|
if (v != NAME_None && v.IsValidName())
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
2006-05-20 09:16:08 +00:00
|
|
|
defaults->AmmoType2 = PClass::FindClass(v);
|
2006-06-17 20:29:41 +00:00
|
|
|
if (isRuntimeActor)
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
2006-06-17 20:29:41 +00:00
|
|
|
if (!defaults->AmmoType2)
|
|
|
|
{
|
|
|
|
I_Error("Unknown ammo type '%s' in '%s'\n", v.GetChars(), ti->TypeName.GetChars());
|
|
|
|
}
|
|
|
|
else if (defaults->AmmoType2->ParentClass != RUNTIME_CLASS(AAmmo))
|
|
|
|
{
|
|
|
|
I_Error("Invalid ammo type '%s' in '%s'\n", v.GetChars(), ti->TypeName.GetChars());
|
|
|
|
}
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
v = defaults->SisterWeaponType;
|
- Fixed: ActorFlagSetOrReset() wasn't receiving the + or - character from
ParseActorProperties().
- Fixed: The decorate FindFlag() function returned flags from ActorFlags
instead of the passed flags set.
- Fixed: The CHT_CHAINSAW, CHT_POWER, CHT_HEALTH, and CHT_RESSURECT needed
NULL player->mo checks.
- Fixed: The "give all" command didn't give the backpack in Doom, and it
must give the backpack before giving ammo.
- Fixed: P_SetPsprite() must not call the action function if the player is
not attached to an actor. This can happen, for instance, if the level is
destroyed while the player is holding a powered-up Phoenix Rod. As part
of its EndPowerup() function, it sets the psprite to the regular version,
but the player actor has already been destroyed.
- Fixed: FinishThingdef() needs to check for valid names, because weapons
could have inherited valid pointers from their superclass.
- Fixed: fuglyname didn't work.
- Fixed: Redefining $ambient sounds leaked memory.
- Added Jim's crashcatcher.c fix for better shell support.
- VC7.1 seems to have no trouble distinguishing between passing a (const
TypeInfo *) reference to operator<< and the generic, templated (object *)
version, so a few places that can benefit from it now use it. I believe
VC6 had problems with this, which is why I didn't do it all along. The
function's implementation was also moved out of dobject.cpp and into
farchive.cpp.
- Fixed: UnpackPixels() unpacked all chunks in a byte, which is wrong for the
last byte in a row if the image width is not an even multiple of the number
pixels per byte.
- Fixed: P_TranslateLineDef() should only clear monster activation for secret
useable lines, not crossable lines.
- Fixed: Some leftover P_IsHostile() calls still needed to be rewritten.
- Fixed: AWeaponHolder::Serialize() wrote the class type in all circumstances.
SVN r20 (trunk)
2006-03-14 06:11:39 +00:00
|
|
|
if (v != NAME_None && v.IsValidName())
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
2006-05-20 09:16:08 +00:00
|
|
|
defaults->SisterWeaponType = PClass::FindClass(v);
|
2006-06-17 20:29:41 +00:00
|
|
|
if (isRuntimeActor)
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
2006-06-17 20:29:41 +00:00
|
|
|
if (!defaults->SisterWeaponType)
|
|
|
|
{
|
|
|
|
I_Error("Unknown sister weapon type '%s' in '%s'\n", v.GetChars(), ti->TypeName.GetChars());
|
|
|
|
}
|
|
|
|
else if (!defaults->SisterWeaponType->IsDescendantOf(RUNTIME_CLASS(AWeapon)))
|
|
|
|
{
|
|
|
|
I_Error("Invalid sister weapon type '%s' in '%s'\n", v.GetChars(), ti->TypeName.GetChars());
|
|
|
|
}
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-06-17 20:29:41 +00:00
|
|
|
if (isRuntimeActor)
|
|
|
|
{
|
|
|
|
// Do some consistency checks. If these states are undefined the weapon cannot work!
|
2006-10-31 14:53:21 +00:00
|
|
|
if (!ti->ActorInfo->FindState(1, NAME_Ready)) I_Error("Weapon %s doesn't define a ready state.\n", ti->TypeName.GetChars());
|
|
|
|
if (!ti->ActorInfo->FindState(1, NAME_Select)) I_Error("Weapon %s doesn't define a select state.\n", ti->TypeName.GetChars());
|
|
|
|
if (!ti->ActorInfo->FindState(1, NAME_Deselect)) I_Error("Weapon %s doesn't define a deselect state.\n", ti->TypeName.GetChars());
|
|
|
|
if (!ti->ActorInfo->FindState(1, NAME_Fire)) I_Error("Weapon %s doesn't define a fire state.\n", ti->TypeName.GetChars());
|
2006-06-17 20:29:41 +00:00
|
|
|
}
|
2006-02-24 04:48:15 +00:00
|
|
|
|
|
|
|
}
|
|
|
|
// same for the weapon type of weapon pieces.
|
|
|
|
else if (ti->IsDescendantOf(RUNTIME_CLASS(AWeaponPiece)))
|
|
|
|
{
|
2006-05-10 02:40:43 +00:00
|
|
|
AWeaponPiece * defaults=(AWeaponPiece *)ti->Defaults;
|
2006-02-24 04:48:15 +00:00
|
|
|
fuglyname v;
|
|
|
|
|
|
|
|
v = defaults->WeaponClass;
|
2006-05-20 09:16:08 +00:00
|
|
|
if (v != NAME_None && v.IsValidName())
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
2006-05-20 09:16:08 +00:00
|
|
|
defaults->WeaponClass = PClass::FindClass(v);
|
2006-02-24 04:48:15 +00:00
|
|
|
if (!defaults->WeaponClass)
|
|
|
|
{
|
2006-06-17 20:29:41 +00:00
|
|
|
I_Error("Unknown weapon type '%s' in '%s'\n", v.GetChars(), ti->TypeName.GetChars());
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
2006-05-20 09:16:08 +00:00
|
|
|
else if (!defaults->WeaponClass->IsDescendantOf(RUNTIME_CLASS(AWeapon)))
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
2006-06-17 20:29:41 +00:00
|
|
|
I_Error("Invalid weapon type '%s' in '%s'\n", v.GetChars(), ti->TypeName.GetChars());
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2006-05-07 00:27:22 +00:00
|
|
|
|
|
|
|
// Since these are defined in DECORATE now the table has to be initialized here.
|
|
|
|
for(int i=0;i<31;i++)
|
|
|
|
{
|
|
|
|
char fmt[20];
|
|
|
|
sprintf(fmt, "QuestItem%d", i+1);
|
2006-05-10 02:40:43 +00:00
|
|
|
QuestItemClasses[i]=PClass::FindClass(fmt);
|
2006-05-07 00:27:22 +00:00
|
|
|
}
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
2006-12-04 23:25:59 +00:00
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
//
|
|
|
|
// ParseClass
|
|
|
|
//
|
|
|
|
// A minimal placeholder so that I can assign properties to some native
|
|
|
|
// classes. Please, no end users use this until it's finalized.
|
|
|
|
//
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
void ParseClass()
|
|
|
|
{
|
|
|
|
Baggage bag;
|
|
|
|
const PClass *cls;
|
|
|
|
FName classname;
|
|
|
|
FName supername;
|
|
|
|
|
|
|
|
SC_MustGetToken(TK_Identifier); // class name
|
|
|
|
classname = sc_Name;
|
|
|
|
SC_MustGetToken(TK_Extends); // because I'm not supporting Object
|
|
|
|
SC_MustGetToken(TK_Identifier); // superclass name
|
|
|
|
supername = sc_Name;
|
|
|
|
SC_MustGetToken(TK_Native); // use actor definitions for your own stuff
|
|
|
|
SC_MustGetToken('{');
|
|
|
|
|
|
|
|
cls = PClass::FindClass (classname);
|
|
|
|
if (cls == NULL)
|
|
|
|
{
|
|
|
|
SC_ScriptError ("'%s' is not a native class", classname.GetChars());
|
|
|
|
}
|
|
|
|
if (cls->ParentClass == NULL || cls->ParentClass->TypeName != supername)
|
|
|
|
{
|
|
|
|
SC_ScriptError ("'%s' does not extend '%s'", classname.GetChars(), supername.GetChars());
|
|
|
|
}
|
|
|
|
bag.Info = cls->ActorInfo;
|
|
|
|
|
|
|
|
SC_MustGetAnyToken();
|
|
|
|
while (sc_TokenType != '}')
|
|
|
|
{
|
|
|
|
if (sc_TokenType == TK_Action)
|
|
|
|
{
|
|
|
|
ActorActionDef (0, bag);
|
|
|
|
}
|
|
|
|
else if (sc_TokenType == TK_Const)
|
|
|
|
{
|
|
|
|
ActorConstDef (0, bag);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2006-12-09 00:16:10 +00:00
|
|
|
FString tokname = SC_TokenName(sc_TokenType, sc_String);
|
|
|
|
SC_ScriptError ("Expected 'action' or 'const' but got %s", tokname.GetChars());
|
2006-12-04 23:25:59 +00:00
|
|
|
}
|
|
|
|
SC_MustGetAnyToken();
|
|
|
|
}
|
|
|
|
}
|