Merge branch 'master' into gonesolong
Conflicts: src/CMakeLists.txt src/b_think.cpp src/g_doom/a_doomweaps.cpp src/g_hexen/a_clericstaff.cpp src/g_hexen/a_fighterplayer.cpp src/namedef.h src/p_enemy.cpp src/p_local.h src/p_mobj.cpp src/p_teleport.cpp src/sc_man_tokens.h src/thingdef/thingdef_codeptr.cpp src/thingdef/thingdef_function.cpp src/thingdef/thingdef_parse.cpp wadsrc/static/actors/actor.txt wadsrc/static/actors/constants.txt wadsrc/static/actors/shared/inventory.txt - Added register reuse to VMFunctionBuilder for FxPick's code emitter. - Note to self: Need to reimplement IsPointerEqual and CheckClass, which were added to thingdef_function.cpp over the past year, as this file no longer exists in this branch.
This commit is contained in:
commit
b5e4153c78
182 changed files with 23025 additions and 8730 deletions
364
src/p_acs.cpp
364
src/p_acs.cpp
|
|
@ -120,6 +120,17 @@ FRandom pr_acs ("ACS");
|
|||
#define SDF_ABSANGLE 1
|
||||
#define SDF_PERMANENT 2
|
||||
|
||||
// GetArmorInfo
|
||||
enum
|
||||
{
|
||||
ARMORINFO_CLASSNAME,
|
||||
ARMORINFO_SAVEAMOUNT,
|
||||
ARMORINFO_SAVEPERCENT,
|
||||
ARMORINFO_MAXABSORB,
|
||||
ARMORINFO_MAXFULLABSORB,
|
||||
ARMORINFO_ACTUALSAVEAMOUNT,
|
||||
};
|
||||
|
||||
struct CallReturn
|
||||
{
|
||||
CallReturn(int pc, ScriptFunction *func, FBehavior *module, SDWORD *locals, ACSLocalArrays *arrays, bool discard, unsigned int runaway)
|
||||
|
|
@ -1570,20 +1581,28 @@ void FBehavior::StaticSerializeModuleStates (FArchive &arc)
|
|||
for (modnum = 0; modnum < StaticModules.Size(); ++modnum)
|
||||
{
|
||||
FBehavior *module = StaticModules[modnum];
|
||||
int ModSize = module->GetDataSize();
|
||||
|
||||
if (arc.IsStoring())
|
||||
{
|
||||
arc.WriteString (module->ModuleName);
|
||||
if (SaveVersion >= 4516) arc << ModSize;
|
||||
}
|
||||
else
|
||||
{
|
||||
char *modname = NULL;
|
||||
arc << modname;
|
||||
if (SaveVersion >= 4516) arc << ModSize;
|
||||
if (stricmp (modname, module->ModuleName) != 0)
|
||||
{
|
||||
delete[] modname;
|
||||
I_Error ("Level was saved with a different set of ACS modules.");
|
||||
}
|
||||
else if (ModSize != module->GetDataSize())
|
||||
{
|
||||
delete[] modname;
|
||||
I_Error("ACS module %s has changed from what was saved. (Have %d bytes, save has %d bytes)", module->ModuleName, module->GetDataSize(), ModSize);
|
||||
}
|
||||
delete[] modname;
|
||||
}
|
||||
module->SerializeVars (arc);
|
||||
|
|
@ -1862,7 +1881,7 @@ FBehavior::FBehavior (int lumpnum, FileReader * fr, int len)
|
|||
funcm->HasReturnValue = funcf->HasReturnValue;
|
||||
funcm->ImportNum = funcf->ImportNum;
|
||||
funcm->LocalCount = funcf->LocalCount;
|
||||
funcm->Address = funcf->Address;
|
||||
funcm->Address = LittleLong(funcf->Address);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2047,7 +2066,7 @@ FBehavior::FBehavior (int lumpnum, FileReader * fr, int len)
|
|||
const char *const parse = (char *)&chunk[2];
|
||||
DWORD i;
|
||||
|
||||
for (i = 0; i < chunk[1]; )
|
||||
for (i = 0; i < LittleLong(chunk[1]); )
|
||||
{
|
||||
if (parse[i])
|
||||
{
|
||||
|
|
@ -2295,6 +2314,12 @@ void FBehavior::LoadScriptsDirectory ()
|
|||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// [EP] Clang 3.5.0 optimizer miscompiles this function and causes random
|
||||
// crashes in the program. I hope that Clang 3.5.x will fix this.
|
||||
#if defined(__clang__) && __clang_major__ == 3 && __clang_minor__ >= 5
|
||||
asm("" : "+g" (NumScripts));
|
||||
#endif
|
||||
for (i = 0; i < NumScripts; ++i)
|
||||
{
|
||||
Scripts[i].Flags = 0;
|
||||
|
|
@ -2334,7 +2359,7 @@ void FBehavior::LoadScriptsDirectory ()
|
|||
scripts.b = FindChunk (MAKE_ID('S','F','L','G'));
|
||||
if (scripts.dw != NULL)
|
||||
{
|
||||
max = scripts.dw[1] / 4;
|
||||
max = LittleLong(scripts.dw[1]) / 4;
|
||||
scripts.dw += 2;
|
||||
for (i = max; i > 0; --i, scripts.w += 2)
|
||||
{
|
||||
|
|
@ -2350,7 +2375,7 @@ void FBehavior::LoadScriptsDirectory ()
|
|||
scripts.b = FindChunk (MAKE_ID('S','V','C','T'));
|
||||
if (scripts.dw != NULL)
|
||||
{
|
||||
max = scripts.dw[1] / 4;
|
||||
max = LittleLong(scripts.dw[1]) / 4;
|
||||
scripts.dw += 2;
|
||||
for (i = max; i > 0; --i, scripts.w += 2)
|
||||
{
|
||||
|
|
@ -2664,7 +2689,7 @@ BYTE *FBehavior::FindChunk (DWORD id) const
|
|||
{
|
||||
return chunk;
|
||||
}
|
||||
chunk += ((DWORD *)chunk)[1] + 8;
|
||||
chunk += LittleLong(((DWORD *)chunk)[1]) + 8;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
|
@ -2672,14 +2697,14 @@ BYTE *FBehavior::FindChunk (DWORD id) const
|
|||
BYTE *FBehavior::NextChunk (BYTE *chunk) const
|
||||
{
|
||||
DWORD id = *(DWORD *)chunk;
|
||||
chunk += ((DWORD *)chunk)[1] + 8;
|
||||
chunk += LittleLong(((DWORD *)chunk)[1]) + 8;
|
||||
while (chunk != NULL && chunk < Data + DataSize)
|
||||
{
|
||||
if (((DWORD *)chunk)[0] == id)
|
||||
{
|
||||
return chunk;
|
||||
}
|
||||
chunk += ((DWORD *)chunk)[1] + 8;
|
||||
chunk += LittleLong(((DWORD *)chunk)[1]) + 8;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
|
@ -2864,9 +2889,57 @@ DACSThinker::~DACSThinker ()
|
|||
void DACSThinker::Serialize (FArchive &arc)
|
||||
{
|
||||
int scriptnum;
|
||||
int scriptcount = 0;
|
||||
|
||||
Super::Serialize (arc);
|
||||
arc << Scripts << LastScript;
|
||||
if (SaveVersion < 4515)
|
||||
arc << Scripts << LastScript;
|
||||
else
|
||||
{
|
||||
if (arc.IsStoring())
|
||||
{
|
||||
DLevelScript *script;
|
||||
script = Scripts;
|
||||
while (script)
|
||||
{
|
||||
scriptcount++;
|
||||
|
||||
// We want to store this list backwards, so we can't loose the last pointer
|
||||
if (script->next == NULL)
|
||||
break;
|
||||
script = script->next;
|
||||
}
|
||||
arc << scriptcount;
|
||||
|
||||
while (script)
|
||||
{
|
||||
arc << script;
|
||||
script = script->prev;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// We are running through this list backwards, so the next entry is the last processed
|
||||
DLevelScript *next = NULL;
|
||||
arc << scriptcount;
|
||||
Scripts = NULL;
|
||||
LastScript = NULL;
|
||||
for (int i = 0; i < scriptcount; i++)
|
||||
{
|
||||
arc << Scripts;
|
||||
|
||||
Scripts->next = next;
|
||||
Scripts->prev = NULL;
|
||||
if (next != NULL)
|
||||
next->prev = Scripts;
|
||||
|
||||
next = Scripts;
|
||||
|
||||
if (i == 0)
|
||||
LastScript = Scripts;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (arc.IsStoring ())
|
||||
{
|
||||
ScriptMap::Iterator it(RunningScripts);
|
||||
|
|
@ -2952,7 +3025,8 @@ void DLevelScript::Serialize (FArchive &arc)
|
|||
DWORD i;
|
||||
|
||||
Super::Serialize (arc);
|
||||
arc << next << prev;
|
||||
if (SaveVersion < 4515)
|
||||
arc << next << prev;
|
||||
|
||||
P_SerializeACSScriptNumber(arc, script, false);
|
||||
|
||||
|
|
@ -3606,6 +3680,7 @@ enum
|
|||
APROP_AttackZOffset = 40,
|
||||
APROP_StencilColor = 41,
|
||||
APROP_Friction = 42,
|
||||
APROP_DamageMultiplier=43,
|
||||
};
|
||||
|
||||
// These are needed for ACS's APROP_RenderStyle
|
||||
|
|
@ -3735,16 +3810,16 @@ void DLevelScript::DoSetActorProperty (AActor *actor, int property, int value)
|
|||
break;
|
||||
|
||||
case APROP_Friendly:
|
||||
if (actor->CountsAsKill()) level.total_monsters--;
|
||||
if (value)
|
||||
{
|
||||
if (actor->CountsAsKill()) level.total_monsters--;
|
||||
actor->flags |= MF_FRIENDLY;
|
||||
}
|
||||
else
|
||||
{
|
||||
actor->flags &= ~MF_FRIENDLY;
|
||||
if (actor->CountsAsKill()) level.total_monsters++;
|
||||
}
|
||||
if (actor->CountsAsKill()) level.total_monsters++;
|
||||
break;
|
||||
|
||||
|
||||
|
|
@ -3795,6 +3870,10 @@ void DLevelScript::DoSetActorProperty (AActor *actor, int property, int value)
|
|||
actor->DamageFactor = value;
|
||||
break;
|
||||
|
||||
case APROP_DamageMultiplier:
|
||||
actor->DamageMultiply = value;
|
||||
break;
|
||||
|
||||
case APROP_MasterTID:
|
||||
AActor *other;
|
||||
other = SingleActorFromTID (value, NULL);
|
||||
|
|
@ -3825,6 +3904,10 @@ void DLevelScript::DoSetActorProperty (AActor *actor, int property, int value)
|
|||
actor->reactiontime = value;
|
||||
break;
|
||||
|
||||
case APROP_MeleeRange:
|
||||
actor->meleerange = value;
|
||||
break;
|
||||
|
||||
case APROP_ViewHeight:
|
||||
if (actor->IsKindOf (RUNTIME_CLASS (APlayerPawn)))
|
||||
static_cast<APlayerPawn *>(actor)->ViewHeight = value;
|
||||
|
|
@ -3862,6 +3945,7 @@ int DLevelScript::GetActorProperty (int tid, int property, const SDWORD *stack,
|
|||
case APROP_Speed: return actor->Speed;
|
||||
case APROP_Damage: return actor->GetMissileDamage(0,1);
|
||||
case APROP_DamageFactor:return actor->DamageFactor;
|
||||
case APROP_DamageMultiplier: return actor->DamageMultiply;
|
||||
case APROP_Alpha: return actor->alpha;
|
||||
case APROP_RenderStyle: for (int style = STYLE_None; style < STYLE_Count; ++style)
|
||||
{ // Check for a legacy render style that matches.
|
||||
|
|
@ -4206,7 +4290,7 @@ int DLevelScript::DoClassifyActor(int tid)
|
|||
{
|
||||
classify |= ACTOR_VOODOODOLL;
|
||||
}
|
||||
if (actor->player->isbot)
|
||||
if (actor->player->Bot != NULL)
|
||||
{
|
||||
classify |= ACTOR_BOT;
|
||||
}
|
||||
|
|
@ -4348,6 +4432,13 @@ enum EACSFunctions
|
|||
ACSF_GetActorPowerupTics,
|
||||
ACSF_ChangeActorAngle,
|
||||
ACSF_ChangeActorPitch, // 80
|
||||
ACSF_GetArmorInfo,
|
||||
ACSF_DropInventory,
|
||||
ACSF_PickActor,
|
||||
ACSF_IsPointerEqual,
|
||||
ACSF_CanRaiseActor,
|
||||
ACSF_SetActorTeleFog, // 86
|
||||
ACSF_SwapActorTeleFog,
|
||||
|
||||
/* Zandronum's - these must be skipped when we reach 99!
|
||||
-100:ResetMap(0),
|
||||
|
|
@ -4652,6 +4743,82 @@ static void SetActorPitch(AActor *activator, int tid, int angle, bool interpolat
|
|||
}
|
||||
}
|
||||
|
||||
static void SetActorTeleFog(AActor *activator, int tid, FName telefogsrc, FName telefogdest)
|
||||
{
|
||||
//Simply put, if it doesn't exist, it won't change. One can use "" in this scenario.
|
||||
PClassActor *check;
|
||||
if (tid == 0)
|
||||
{
|
||||
if (activator != NULL)
|
||||
{
|
||||
check = PClass::FindActor(telefogsrc);
|
||||
if (check == NULL || !stricmp(telefogsrc, "none") || !stricmp(telefogsrc, "null"))
|
||||
activator->TeleFogSourceType = NULL;
|
||||
else
|
||||
activator->TeleFogSourceType = check;
|
||||
|
||||
check = PClass::FindActor(telefogdest);
|
||||
if (check == NULL || !stricmp(telefogdest, "none") || !stricmp(telefogdest, "null"))
|
||||
activator->TeleFogDestType = NULL;
|
||||
else
|
||||
activator->TeleFogDestType = check;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
FActorIterator iterator(tid);
|
||||
AActor *actor;
|
||||
|
||||
while ((actor = iterator.Next()))
|
||||
{
|
||||
check = PClass::FindActor(telefogsrc);
|
||||
if (check == NULL || !stricmp(telefogsrc, "none") || !stricmp(telefogsrc, "null"))
|
||||
actor->TeleFogSourceType = NULL;
|
||||
else
|
||||
actor->TeleFogSourceType = check;
|
||||
|
||||
check = PClass::FindActor(telefogdest);
|
||||
if (check == NULL || !stricmp(telefogdest, "none") || !stricmp(telefogdest, "null"))
|
||||
actor->TeleFogDestType = NULL;
|
||||
else
|
||||
actor->TeleFogDestType = check;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int SwapActorTeleFog(AActor *activator, int tid)
|
||||
{
|
||||
int count = 0;
|
||||
if (tid == 0)
|
||||
{
|
||||
if ((activator == NULL) || (activator->TeleFogSourceType = activator->TeleFogDestType))
|
||||
return 0; //Does nothing if they're the same.
|
||||
else
|
||||
{
|
||||
PClassActor *temp = activator->TeleFogSourceType;
|
||||
activator->TeleFogSourceType = activator->TeleFogDestType;
|
||||
activator->TeleFogDestType = temp;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
FActorIterator iterator(tid);
|
||||
AActor *actor;
|
||||
|
||||
while ((actor = iterator.Next()))
|
||||
{
|
||||
if (actor->TeleFogSourceType == actor->TeleFogDestType)
|
||||
continue; //They're the same. Save the effort.
|
||||
PClassActor *temp = actor->TeleFogSourceType;
|
||||
actor->TeleFogSourceType = actor->TeleFogDestType;
|
||||
actor->TeleFogDestType = temp;
|
||||
count++;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int DLevelScript::CallFunction(int argCount, int funcIndex, SDWORD *args, const SDWORD *stack, int stackdepth)
|
||||
|
|
@ -4814,6 +4981,41 @@ int DLevelScript::CallFunction(int argCount, int funcIndex, SDWORD *args, const
|
|||
return 0;
|
||||
}
|
||||
|
||||
case ACSF_GetArmorInfo:
|
||||
{
|
||||
if (activator == NULL || activator->player == NULL) return 0;
|
||||
|
||||
ABasicArmor * equippedarmor = (ABasicArmor *) activator->FindInventory(NAME_BasicArmor);
|
||||
|
||||
if (equippedarmor && equippedarmor->Amount != 0)
|
||||
{
|
||||
switch(args[0])
|
||||
{
|
||||
case ARMORINFO_CLASSNAME:
|
||||
return GlobalACSStrings.AddString(equippedarmor->ArmorType.GetChars(), stack, stackdepth);
|
||||
|
||||
case ARMORINFO_SAVEAMOUNT:
|
||||
return equippedarmor->MaxAmount;
|
||||
|
||||
case ARMORINFO_SAVEPERCENT:
|
||||
return equippedarmor->SavePercent;
|
||||
|
||||
case ARMORINFO_MAXABSORB:
|
||||
return equippedarmor->MaxAbsorb;
|
||||
|
||||
case ARMORINFO_MAXFULLABSORB:
|
||||
return equippedarmor->MaxFullAbsorb;
|
||||
|
||||
case ARMORINFO_ACTUALSAVEAMOUNT:
|
||||
return equippedarmor->ActualSaveAmount;
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return args[0] == ARMORINFO_CLASSNAME ? GlobalACSStrings.AddString("None", stack, stackdepth) : 0;
|
||||
}
|
||||
|
||||
case ACSF_SpawnSpotForced:
|
||||
return DoSpawnSpot(args[0], args[1], args[2], args[3], true);
|
||||
|
||||
|
|
@ -5430,6 +5632,42 @@ doplaysound: if (funcIndex == ACSF_PlayActorSound)
|
|||
break;
|
||||
}
|
||||
|
||||
case ACSF_DropInventory:
|
||||
{
|
||||
const char *type = FBehavior::StaticLookupString(args[1]);
|
||||
AInventory *inv;
|
||||
|
||||
if (type != NULL)
|
||||
{
|
||||
if (args[0] == 0)
|
||||
{
|
||||
if (activator != NULL)
|
||||
{
|
||||
inv = activator->FindInventory(type);
|
||||
if (inv)
|
||||
{
|
||||
activator->DropInventory(inv);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
FActorIterator it(args[0]);
|
||||
AActor *actor;
|
||||
|
||||
while ((actor = it.Next()) != NULL)
|
||||
{
|
||||
inv = actor->FindInventory(type);
|
||||
if (inv)
|
||||
{
|
||||
actor->DropInventory(inv);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case ACSF_CheckFlag:
|
||||
{
|
||||
AActor *actor = SingleActorFromTID(args[0], activator);
|
||||
|
|
@ -5494,6 +5732,97 @@ doplaysound: if (funcIndex == ACSF_PlayActorSound)
|
|||
SetActorPitch(activator, args[0], args[1], argCount > 2 ? !!args[2] : false);
|
||||
}
|
||||
break;
|
||||
case ACSF_SetActorTeleFog:
|
||||
if (argCount >= 3)
|
||||
{
|
||||
SetActorTeleFog(activator, args[0], FBehavior::StaticLookupString(args[1]), FBehavior::StaticLookupString(args[2]));
|
||||
}
|
||||
break;
|
||||
case ACSF_SwapActorTeleFog:
|
||||
if (argCount >= 1)
|
||||
{
|
||||
return SwapActorTeleFog(activator, args[0]);
|
||||
}
|
||||
break;
|
||||
case ACSF_PickActor:
|
||||
if (argCount >= 5)
|
||||
{
|
||||
actor = SingleActorFromTID(args[0], activator);
|
||||
if (actor == NULL)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
DWORD actorMask = MF_SHOOTABLE;
|
||||
if (argCount >= 6) {
|
||||
actorMask = args[5];
|
||||
}
|
||||
|
||||
DWORD wallMask = ML_BLOCKEVERYTHING | ML_BLOCKHITSCAN;
|
||||
if (argCount >= 7) {
|
||||
wallMask = args[6];
|
||||
}
|
||||
|
||||
bool forceTID = 0;
|
||||
if (argCount >= 8)
|
||||
{
|
||||
if (args[7] != 0)
|
||||
forceTID = 1;
|
||||
}
|
||||
|
||||
AActor* pickedActor = P_LinePickActor(actor, args[1] << 16, args[3], args[2] << 16, actorMask, wallMask);
|
||||
if (pickedActor == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(forceTID) && (args[4] == 0) && (pickedActor->tid == 0))
|
||||
return 0;
|
||||
|
||||
if ((pickedActor->tid == 0) || (forceTID))
|
||||
{
|
||||
pickedActor->RemoveFromHash();
|
||||
pickedActor->tid = args[4];
|
||||
pickedActor->AddToHash();
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case ACSF_IsPointerEqual:
|
||||
{
|
||||
int tid1 = 0, tid2 = 0;
|
||||
switch (argCount)
|
||||
{
|
||||
case 4: tid2 = args[3];
|
||||
case 3: tid1 = args[2];
|
||||
}
|
||||
|
||||
actor = SingleActorFromTID(tid1, activator);
|
||||
AActor * actor2 = tid2 == tid1 ? actor : SingleActorFromTID(tid2, activator);
|
||||
|
||||
return COPY_AAPTR(actor, args[0]) == COPY_AAPTR(actor2, args[1]);
|
||||
}
|
||||
break;
|
||||
|
||||
case ACSF_CanRaiseActor:
|
||||
if (argCount >= 1) {
|
||||
if (args[0] == 0) {
|
||||
actor = SingleActorFromTID(args[0], activator);
|
||||
if (actor != NULL) {
|
||||
return P_Thing_CanRaise(actor);
|
||||
}
|
||||
}
|
||||
|
||||
FActorIterator iterator(args[0]);
|
||||
bool canraiseall = false;
|
||||
while ((actor = iterator.Next()))
|
||||
{
|
||||
canraiseall = !P_Thing_CanRaise(actor) | canraiseall;
|
||||
}
|
||||
|
||||
return !canraiseall;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
|
|
@ -7111,7 +7440,7 @@ scriptwait:
|
|||
while (min <= max)
|
||||
{
|
||||
int mid = (min + max) / 2;
|
||||
SDWORD caseval = pc[mid*2];
|
||||
SDWORD caseval = LittleLong(pc[mid*2]);
|
||||
if (caseval == STACK(1))
|
||||
{
|
||||
pc = activeBehavior->Ofs2PC (LittleLong(pc[mid*2+1]));
|
||||
|
|
@ -7477,13 +7806,6 @@ scriptwait:
|
|||
AddToConsole (-1, consolecolor);
|
||||
AddToConsole (-1, work);
|
||||
AddToConsole (-1, bar);
|
||||
if (Logfile)
|
||||
{
|
||||
fputs (logbar, Logfile);
|
||||
fputs (work, Logfile);
|
||||
fputs (logbar, Logfile);
|
||||
fflush (Logfile);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -8459,7 +8781,7 @@ scriptwait:
|
|||
}
|
||||
else
|
||||
{
|
||||
STACK(1) = players[STACK(1)].isbot;
|
||||
STACK(1) = (players[STACK(1)].Bot != NULL);
|
||||
}
|
||||
break;
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue