void P_SetupWeapons_ntohton() { unsigned int i; const PClass *cls; Weapons_ntoh.Clear(); Weapons_hton.Clear(); cls = NULL; Weapons_ntoh.Push(cls); // Index 0 is always NULL. for (i = 0; i < PClass::m_Types.Size(); ++i) { PClass *cls = PClass::m_Types[i]; if (cls->ActorInfo != NULL && cls->IsDescendantOf(RUNTIME_CLASS(AWeapon))) { Weapons_ntoh.Push(cls); } } qsort(&Weapons_ntoh[1], Weapons_ntoh.Size() - 1, sizeof(Weapons_ntoh[0]), ntoh_cmp); for (i = 0; i < Weapons_ntoh.Size(); ++i) { Weapons_hton[Weapons_ntoh[i]] = i; } }
void UCContext::emit_native_function_call(Function *pfn, CALLFN fn) { Type rt = pfn->return_type(); // *change 1.2.0 Moved from compile_function_call() // for cdecl-style method imports, if (pfn->is_cdecl() && pfn->is_method()) { // push mOP onto exec stack emit(PUSH_THIS,0); // do note that returned objects are by a another hidden arg // *fix 1.1.4 The return type must specifically be an _object_, not a pointer to an object! if (rt.is_object()) emit(SWAP,0); } emit(CALLN,DIRECT,NFBlock::create(pfn,fn)); pfn->fun_block()->data = (void *)fn; // convenient place to keep this! // We need to check imported class object ptrs to see if they have a VMT.... // Any imported class ptrs need their UC VMT patched with CHKVMT // *fix 1.1.0 Imported references as well as pointers! if (rt.is_class() && rt.is_ref_or_ptr()) { PClass pc = pc = rt.as_class(); if (pc->imported() && pc->has_VMT()) out(CodeGenerator::instruction_with_pointer(CHKVMT,pc)); } // *add 1.2.9 Sometimes necessary to clear out upper 3bytes of 32-bit boolean values else if (rt == t_bool) { emit(I2B); } }
static void SetKeyTypes() { for(unsigned int i = 0; i < PClassActor::AllActorClasses.Size(); i++) { PClass *ti = PClassActor::AllActorClasses[i]; if (ti->IsDescendantOf(RUNTIME_CLASS(AKey))) { PClassActor *tia = static_cast<PClassActor *>(ti); AKey *key = (AKey*)GetDefaultByType(tia); if (key->Icon.isValid() && key->KeyNumber>0) { KeyTypes.Push(tia); } else { UnassignedKeyTypes.Push(tia); } } } if (KeyTypes.Size()) { qsort(&KeyTypes[0], KeyTypes.Size(), sizeof(KeyTypes[0]), ktcmp); } else { // Don't leave the list empty PClassActor *ti = RUNTIME_CLASS(AKey); KeyTypes.Push(ti); } }
static void SetKeyTypes() { for(unsigned int i = 0; i < PClassActor::AllActorClasses.Size(); i++) { PClass *ti = PClassActor::AllActorClasses[i]; auto kt = PClass::FindActor(NAME_Key); if (ti->IsDescendantOf(kt)) { PClassActor *tia = static_cast<PClassActor *>(ti); AInventory *key = (AInventory*)(GetDefaultByType(tia)); if (key->Icon.isValid() && key->special1 > 0) { KeyTypes.Push(tia); } else { UnassignedKeyTypes.Push(tia); } } } if (KeyTypes.Size()) { qsort(&KeyTypes[0], KeyTypes.Size(), sizeof(KeyTypes[0]), ktcmp); } else { // Don't leave the list empty KeyTypes.Push(PClass::FindActor(NAME_Key)); } }
// miscelaneous output routines ostream& operator << (ostream& os, Signature& sig) { Signature::iterator si; StringList::iterator sli; StringList *args = sig.get_arg_names(); if (args && args->size()==0) args = NULL; if (!s_ctor && !s_dtor) // *fix 1.1.2 these don't have return types! os << sig.return_type() << ' '; string na = s_fun_name; char first = na[0]; // *fix 1.2.7 wasn't outputing 'operator' in front of '()' if (!isalpha(first) && first != '_' /*&& first != '('*/) na = "operator" + na; PClass pc = sig.class_ptr(); if (pc != NULL) { string classn = pc->name(); if (! s_full_names && pc->is_template()) classn = pc->get_template()->name(); if (s_ctor) na = classn; else if (s_dtor) na = "~" + classn; if (s_full_names) na = classn + "::" + na; } os << na << '('; if (args != NULL) sli = args->begin(); for(si = sig.begin(); si != sig.end(); ) { os << *si++; if (args != NULL) os << ' ' << *sli++; if (si != sig.end()) os << ','; } os << ')'; if (sig.is_const()) os << " const"; return os; }
void dissemble(PFBlock fb) { Opcodes opcode; int rmode,rdata, k = 0; string name; Instruction *pi = fb->pstart; while (pi != end_of_code) { opcode = (Opcodes)pi->opcode; // *add 1.2.4 HALT+data is not always a breakpoint! // (it is used as a NOP + <any useful tag data>) if (opcode == HALT) { if (pi->data < MAX_BREAKPOINTS) { Breakpoint *pb = Breakpoint::from_id(pi->data); Instruction ai = pb->saved_instruction(); std::cout << "*"; opcode = (Opcodes)ai.opcode; rmode = ai.rmode; rdata = ai.data; } else { opcode = NOP; rdata = pi->data; } } else { rmode = pi->rmode; rdata = pi->data; } name = get_opcode_name(opcode); std::cout << k++ << ' ' << name << '\t'; if (opcode == CCALL || opcode == CALL || opcode == CALLD || opcode == CALLN) { FBlock* pfb; void *data = data_ptr(rdata); if (opcode == CALLN) pfb = Builtin::imported_fblock_from_function((void*)((NFBlock *)data)->pfn); else pfb = PFBlock(data_ptr(rdata)); if (pfb) Function::from_fun_block(pfb)->dump(std::cout); } else if (opcode == JSWITCH) { int *swb = (int *)data_ptr(rdata); int sz = *swb++; int def = *swb++; std::cout << '(' << sz << ',' << def << ") "; for (int i = 0; i < sz; i++) std::cout << *swb++ << ' ' << *swb++ << ' '; } else if (opcode == TOSD || opcode == TPODS) { PClass pc = *(PClass *)data_ptr(rdata); std::cout << pc->name(); } else { if (rmode) switch(rmode) { case DIRECT: std::cout << "D "; break; case SREL: std::cout << "R "; break; case OREL: std::cout << "S "; break; } if (rdata != 0) std::cout << rdata; } std::cout << std::endl; if (opcode == RET || opcode == RETI || opcode == RETD) break; pi++; } }
DObject::~DObject () { if (!PClass::bShutdown) { PClass *type = GetClass(); if (!(ObjectFlags & OF_Cleanup) && !PClass::bShutdown) { DObject **probe; if (!(ObjectFlags & OF_YesReallyDelete)) { Printf("Warning: '%s' is freed outside the GC process.\n", type != NULL ? type->TypeName.GetChars() : "==some object=="); } // Find all pointers that reference this object and NULL them. StaticPointerSubstitution(this, NULL); // Now unlink this object from the GC list. for (probe = &GC::Root; *probe != NULL; probe = &((*probe)->ObjNext)) { if (*probe == this) { *probe = ObjNext; if (&ObjNext == GC::SweepPos) { GC::SweepPos = probe; } break; } } // If it's gray, also unlink it from the gray list. if (this->IsGray()) { for (probe = &GC::Gray; *probe != NULL; probe = &((*probe)->GCNext)) { if (*probe == this) { *probe = GCNext; break; } } } } if (nullptr != type) { type->DestroySpecials(this); } } }
PClass *PClass::CreateDerivedClass(FName name, unsigned int size) { assert(size >= Size); PClass *type; bool notnew; const PClass *existclass = FindClass(name); if (existclass != nullptr) { // This is a placeholder so fill it in if (existclass->Size == TentativeClass) { type = const_cast<PClass*>(existclass); if (!IsDescendantOf(type->ParentClass)) { I_Error("%s must inherit from %s but doesn't.", name.GetChars(), type->ParentClass->TypeName.GetChars()); } DPrintf(DMSG_SPAMMY, "Defining placeholder class %s\n", name.GetChars()); notnew = true; } else { // a different class with the same name already exists. Let the calling code deal with this. return nullptr; } } else { type = new PClass; notnew = false; } type->TypeName = name; type->bRuntimeClass = true; Derive(type, name); type->Size = size; if (size != TentativeClass) { NewClassType(type); type->InitializeDefaults(); type->Virtuals = Virtuals; } else type->bOptional = false; if (!notnew) { type->InsertIntoHash(false); } return type; }
PClass *ClassReg::RegisterClass() { // Skip classes that have already been registered if (MyClass != nullptr) { return MyClass; } // Add type to list PClass *cls = new PClass; SetupClass(cls); cls->InsertIntoHash(true); if (ParentType != nullptr) { cls->ParentClass = ParentType->RegisterClass(); } return cls; }
PClass *PClass::FindClassTentative(FName name) { if (name == NAME_None) { return nullptr; } PClass *found = FindClass(name); if (found != nullptr) return found; PClass *type = new PClass; DPrintf(DMSG_SPAMMY, "Creating placeholder class %s : %s\n", name.GetChars(), TypeName.GetChars()); Derive(type, name); type->Size = TentativeClass; type->InsertIntoHash(false); return type; }
// Create a new class based on an existing class PClass *PClass::CreateDerivedClass (FName name, unsigned int size) { assert (size >= Size); PClass *type = new PClass; type->TypeName = name; type->ParentClass = this; type->Size = size; type->Pointers = NULL; type->ConstructNative = ConstructNative; type->ClassIndex = m_Types.Push (type); type->Meta = Meta; type->Defaults = new BYTE[size]; memcpy (type->Defaults, Defaults, Size); if (size > Size) { memset (type->Defaults + Size, 0, size - Size); } type->FlatPointers = NULL; type->bRuntimeClass = true; type->ActorInfo = NULL; type->InsertIntoHash(); // If this class has an actor info, then any classes derived from it // also need an actor info. if (this->ActorInfo != NULL) { FActorInfo *info = type->ActorInfo = new FActorInfo; info->Class = type; info->GameFilter = GAME_Any; info->SpawnID = 0; info->DoomEdNum = -1; info->OwnedStates = NULL; info->NumOwnedStates = 0; info->Replacement = NULL; info->Replacee = NULL; m_RuntimeActors.Push (type); } return type; }
// Like FindClass but creates a placeholder if no class // is found. CreateDerivedClass will automatcally fill in // the placeholder when the actual class is defined. const PClass *PClass::FindClassTentative (FName name) { if (name == NAME_None) { return NULL; } PClass *cls = TypeHash[name % HASH_SIZE]; while (cls != 0) { int lexx = int(name) - int(cls->TypeName); if (lexx > 0) { cls = cls->HashNext; } else if (lexx == 0) { return cls; } else { break; } } PClass *type = new PClass; DPrintf("Creating placeholder class %s : %s\n", name.GetChars(), TypeName.GetChars()); type->TypeName = name; type->ParentClass = this; type->Size = -1; type->Pointers = NULL; type->ConstructNative = NULL; type->ClassIndex = m_Types.Push (type); type->Defaults = NULL; type->FlatPointers = NULL; type->bRuntimeClass = true; type->ActorInfo = NULL; type->InsertIntoHash(); return type; }
void FWeaponSlots::AddExtraWeapons() { unsigned int i; // Set fractional positions for current weapons. for (i = 0; i < NUM_WEAPON_SLOTS; ++i) { Slots[i].SetInitialPositions(); } // Append extra weapons to the slots. for (unsigned int i = 0; i < PClassActor::AllActorClasses.Size(); ++i) { PClass *cls = PClassActor::AllActorClasses[i]; if (!cls->IsDescendantOf(RUNTIME_CLASS(AWeapon))) { continue; } PClassWeapon *acls = static_cast<PClassWeapon *>(cls); if ((acls->GameFilter == GAME_Any || (acls->GameFilter & gameinfo.gametype)) && acls->Replacement == NULL && // Replaced weapons don't get slotted. !(((AWeapon *)(acls->Defaults))->WeaponFlags & WIF_POWERED_UP) && !LocateWeapon(acls, NULL, NULL) // Don't duplicate it if it's already present. ) { int slot = acls->SlotNumber; if ((unsigned)slot < NUM_WEAPON_SLOTS) { FWeaponSlot::WeaponInfo info = { acls, acls->SlotPriority }; Slots[slot].Weapons.Push(info); } } } // Now resort every slot to put the new weapons in their proper places. for (i = 0; i < NUM_WEAPON_SLOTS; ++i) { Slots[i].Sort(); } }
static void FinishThingdef() { int errorcount = StateParams.ResolveAll(); for (unsigned i = 0;i < PClass::m_Types.Size(); i++) { PClass * ti = PClass::m_Types[i]; // Skip non-actors if (!ti->IsDescendantOf(RUNTIME_CLASS(AActor))) continue; if (ti->Size == (unsigned)-1) { Printf("Class %s referenced but not defined\n", ti->TypeName.GetChars()); errorcount++; continue; } AActor *def = GetDefaultByType(ti); if (!def) { Printf("No ActorInfo defined for class '%s'\n", ti->TypeName.GetChars()); errorcount++; continue; } } if (errorcount > 0) { I_Error("%d errors during actor postprocessing", errorcount); } // Since these are defined in DECORATE now the table has to be initialized here. for(int i=0;i<31;i++) { char fmt[20]; mysnprintf(fmt, countof(fmt), "QuestItem%d", i+1); QuestItemClasses[i] = PClass::FindClass(fmt); } }
void FWeaponSlots::AddExtraWeapons() { unsigned int i; // Set fractional positions for current weapons. for (i = 0; i < NUM_WEAPON_SLOTS; ++i) { Slots[i].SetInitialPositions(); } // Append extra weapons to the slots. for (unsigned int i = 0; i < PClass::m_Types.Size(); ++i) { PClass *cls = PClass::m_Types[i]; if (cls->ActorInfo != NULL && (cls->ActorInfo->GameFilter == GAME_Any || (cls->ActorInfo->GameFilter & gameinfo.gametype)) && cls->ActorInfo->Replacement == NULL && // Replaced weapons don't get slotted. cls->IsDescendantOf(RUNTIME_CLASS(AWeapon)) && !(static_cast<AWeapon*>(GetDefaultByType(cls))->WeaponFlags & WIF_POWERED_UP) && !LocateWeapon(cls, NULL, NULL) // Don't duplicate it if it's already present. ) { int slot = cls->Meta.GetMetaInt(AWMETA_SlotNumber, -1); if ((unsigned)slot < NUM_WEAPON_SLOTS) { fixed_t position = cls->Meta.GetMetaFixed(AWMETA_SlotPriority, INT_MAX); FWeaponSlot::WeaponInfo info = { cls, position }; Slots[slot].Weapons.Push(info); } } } // Now resort every slot to put the new weapons in their proper places. for (i = 0; i < NUM_WEAPON_SLOTS; ++i) { Slots[i].Sort(); } }
void FinishActor(const FScriptPosition &sc, FActorInfo *info, Baggage &bag) { PClass *ti = info->Class; AActor *defaults = (AActor*)ti->Defaults; try { bag.statedef.FinishStates (info, defaults); } catch (CRecoverableError &err) { sc.Message(MSG_ERROR, "%s", err.GetMessage()); bag.statedef.MakeStateDefines(NULL); return; } bag.statedef.InstallStates (info, defaults); bag.statedef.MakeStateDefines(NULL); if (bag.DropItemSet) { if (bag.DropItemList == NULL) { if (ti->Meta.GetMetaInt (ACMETA_DropItems) != 0) { ti->Meta.SetMetaInt (ACMETA_DropItems, 0); } } else { ti->Meta.SetMetaInt (ACMETA_DropItems, StoreDropItemChain(bag.DropItemList)); } } if (ti->IsDescendantOf (RUNTIME_CLASS(AInventory))) { defaults->flags |= MF_SPECIAL; } // Weapons must be checked for all relevant states. They may crash the game otherwise. if (ti->IsDescendantOf(RUNTIME_CLASS(AWeapon))) { FState * ready = ti->ActorInfo->FindState(NAME_Ready); FState * select = ti->ActorInfo->FindState(NAME_Select); FState * deselect = ti->ActorInfo->FindState(NAME_Deselect); FState * fire = ti->ActorInfo->FindState(NAME_Fire); // Consider any weapon without any valid state abstract and don't output a warning // This is for creating base classes for weapon groups that only set up some properties. if (ready || select || deselect || fire) { if (!ready) { sc.Message(MSG_ERROR, "Weapon %s doesn't define a ready state.\n", ti->TypeName.GetChars()); } if (!select) { sc.Message(MSG_ERROR, "Weapon %s doesn't define a select state.\n", ti->TypeName.GetChars()); } if (!deselect) { sc.Message(MSG_ERROR, "Weapon %s doesn't define a deselect state.\n", ti->TypeName.GetChars()); } if (!fire) { sc.Message(MSG_ERROR, "Weapon %s doesn't define a fire state.\n", ti->TypeName.GetChars()); } } } }
void cht_Take (player_t *player, const char *name, int amount) { bool takeall; PClassActor *type; if (player->mo == NULL || player->health <= 0) { return; } takeall = (stricmp (name, "all") == 0); if (!takeall && stricmp (name, "health") == 0) { if (player->mo->health - amount <= 0 || player->health - amount <= 0 || amount == 0) { cht_Suicide (player); if (player == &players[consoleplayer]) C_HideConsole (); return; } if (amount > 0) { if (player->mo) { player->mo->health -= amount; player->health = player->mo->health; } else { player->health -= amount; } } if (!takeall) return; } if (takeall || stricmp (name, "backpack") == 0) { // Take away all types of backpacks the player might own. for (unsigned int i = 0; i < PClassActor::AllActorClasses.Size(); ++i) { PClass *type = PClassActor::AllActorClasses[i]; if (type->IsDescendantOf(RUNTIME_CLASS (ABackpackItem))) { AInventory *pack = player->mo->FindInventory(static_cast<PClassActor *>(type)); if (pack) pack->Destroy(); } } if (!takeall) return; } if (takeall || stricmp (name, "ammo") == 0) { for (unsigned int i = 0; i < PClassActor::AllActorClasses.Size(); ++i) { PClass *type = PClassActor::AllActorClasses[i]; if (type->ParentClass == RUNTIME_CLASS (AAmmo)) { AInventory *ammo = player->mo->FindInventory(static_cast<PClassActor *>(type)); if (ammo) ammo->DepleteOrDestroy(); } } if (!takeall) return; } if (takeall || stricmp (name, "armor") == 0) { for (unsigned int i = 0; i < PClassActor::AllActorClasses.Size(); ++i) { type = PClassActor::AllActorClasses[i]; if (type->IsDescendantOf (RUNTIME_CLASS (AArmor))) { AInventory *armor = player->mo->FindInventory(static_cast<PClassActor *>(type)); if (armor) armor->DepleteOrDestroy(); } } if (!takeall) return; } if (takeall || stricmp (name, "keys") == 0) { for (unsigned int i = 0; i < PClassActor::AllActorClasses.Size(); ++i) { type = PClassActor::AllActorClasses[i]; if (type->IsDescendantOf (RUNTIME_CLASS (AKey))) { AActor *key = player->mo->FindInventory(static_cast<PClassActor *>(type)); if (key) key->Destroy (); } } if (!takeall) return; } if (takeall || stricmp (name, "weapons") == 0) { for (unsigned int i = 0; i < PClassActor::AllActorClasses.Size(); ++i) { type = PClassActor::AllActorClasses[i]; if (type != RUNTIME_CLASS(AWeapon) && type->IsDescendantOf (RUNTIME_CLASS (AWeapon))) { AActor *weapon = player->mo->FindInventory(static_cast<PClassActor *>(type)); if (weapon) weapon->Destroy (); player->ReadyWeapon = nullptr; player->PendingWeapon = WP_NOCHANGE; } } if (!takeall) return; } if (takeall || stricmp (name, "artifacts") == 0) { for (unsigned int i = 0; i < PClassActor::AllActorClasses.Size(); ++i) { type = PClassActor::AllActorClasses[i]; if (type->IsDescendantOf (RUNTIME_CLASS (AInventory))) { if (!type->IsDescendantOf (RUNTIME_CLASS (APuzzleItem)) && !type->IsDescendantOf (RUNTIME_CLASS (APowerup)) && !type->IsDescendantOf (RUNTIME_CLASS (AArmor)) && !type->IsDescendantOf (RUNTIME_CLASS (AWeapon)) && !type->IsDescendantOf (RUNTIME_CLASS (AKey))) { AActor *artifact = player->mo->FindInventory(static_cast<PClassActor *>(type)); if (artifact) artifact->Destroy (); } } } if (!takeall) return; } if (takeall || stricmp (name, "puzzlepieces") == 0) { for (unsigned int i = 0; i < PClassActor::AllActorClasses.Size(); ++i) { type = PClassActor::AllActorClasses[i]; if (type->IsDescendantOf (RUNTIME_CLASS (APuzzleItem))) { AActor *puzzlepiece = player->mo->FindInventory(static_cast<PClassActor *>(type)); if (puzzlepiece) puzzlepiece->Destroy (); } } if (!takeall) return; } if (takeall) return; type = PClass::FindActor (name); if (type == NULL || !type->IsDescendantOf (RUNTIME_CLASS (AInventory))) { if (player == &players[consoleplayer]) Printf ("Unknown item \"%s\"\n", name); } else { player->mo->TakeInventory(type, amount ? amount : 1); } return; }
void NETWORK_Construct( USHORT usPort, bool bAllocateLANSocket ) { char szString[128]; ULONG ulArg; USHORT usNewPort; bool bSuccess; // Initialize the Huffman buffer. HUFFMAN_Construct( ); #ifdef __WIN32__ // [BB] Linux doesn't know WSADATA, so this may not be moved outside the ifdef. WSADATA WSAData; if ( WSAStartup( 0x0101, &WSAData )) network_Error( "Winsock initialization failed!\n" ); Printf( "Winsock initialization succeeded!\n" ); #endif ULONG ulInAddr = INADDR_ANY; const char* pszIPAddress = Args->CheckValue( "-useip" ); // [BB] An IP was specfied. Check if it's valid and if it is, try to bind our socket to it. if ( pszIPAddress ) { ULONG requestedIP = inet_addr( pszIPAddress ); if ( requestedIP == INADDR_NONE ) { sprintf( szString, "NETWORK_Construct: %s is not a valid IP address\n", pszIPAddress ); network_Error( szString ); } else ulInAddr = requestedIP; } g_usLocalPort = usPort; // Allocate a socket, and attempt to bind it to the given port. g_NetworkSocket = network_AllocateSocket( ); // [BB] If we can't allocate a socket, sending / receiving net packets won't work. if ( g_NetworkSocket == INVALID_SOCKET ) network_Error( "NETWORK_Construct: Couldn't allocate socket. You will not be able to host or join servers.\n" ); else if ( network_BindSocketToPort( g_NetworkSocket, ulInAddr, g_usLocalPort, false ) == false ) { bSuccess = true; bool bSuccessIP = true; usNewPort = g_usLocalPort; while ( network_BindSocketToPort( g_NetworkSocket, ulInAddr, ++usNewPort, false ) == false ) { // Didn't find an available port. Oh well... if ( usNewPort == g_usLocalPort ) { // [BB] We couldn't use the specified IP, so just try any. if ( ulInAddr != INADDR_ANY ) { ulInAddr = INADDR_ANY; bSuccessIP = false; continue; } bSuccess = false; break; } } if ( bSuccess == false ) { sprintf( szString, "NETWORK_Construct: Couldn't bind socket to port: %d\n", g_usLocalPort ); network_Error( szString ); } else if ( bSuccessIP == false ) { sprintf( szString, "NETWORK_Construct: Couldn't bind socket to IP %s, using the default IP instead:\n", pszIPAddress ); network_Error( szString ); } else { Printf( "NETWORK_Construct: Couldn't bind to %d. Binding to %d instead...\n", g_usLocalPort, usNewPort ); g_usLocalPort = usNewPort; } } ulArg = true; if ( ioctlsocket( g_NetworkSocket, FIONBIO, &ulArg ) == -1 ) printf( "network_AllocateSocket: ioctl FIONBIO: %s", strerror( errno )); // If we're not starting a server, setup a socket to listen for LAN servers. if ( bAllocateLANSocket ) { g_LANSocket = network_AllocateSocket( ); if ( network_BindSocketToPort( g_LANSocket, ulInAddr, DEFAULT_BROADCAST_PORT, true ) == false ) { sprintf( szString, "network_BindSocketToPort: Couldn't bind LAN socket to port: %d. You will not be able to see LAN servers in the browser.", DEFAULT_BROADCAST_PORT ); network_Error( szString ); // [BB] The socket won't work in this case, make sure not to use it. g_bLANSocketInvalid = true; } if ( ioctlsocket( g_LANSocket, FIONBIO, &ulArg ) == -1 ) printf( "network_AllocateSocket: ioctl FIONBIO: %s", strerror( errno )); } // Init our read buffer. // [BB] Vortex Cortex pointed us to the fact that the smallest huffman code is only 3 bits // and it turns into 8 bits when it's decompressed. Thus we need to allocate a buffer that // can hold the biggest possible size we may get after decompressing (aka Huffman decoding) // the incoming UDP packet. NETWORK_InitBuffer( &g_NetworkMessage, ((MAX_UDP_PACKET * 8) / 3 + 1), BUFFERTYPE_READ ); NETWORK_ClearBuffer( &g_NetworkMessage ); // [BB] Get and save our local IP. if ( ( ulInAddr == INADDR_ANY ) || ( pszIPAddress == NULL ) ) g_LocalAddress = NETWORK_GetLocalAddress( ); // [BB] We are using a specified IP, so we don't need to figure out what IP we have, but just use the specified one. else { NETWORK_StringToAddress ( pszIPAddress, &g_LocalAddress ); g_LocalAddress.usPort = htons ( NETWORK_GetLocalPort() ); } // Print out our local IP address. Printf( "IP address %s\n", NETWORK_AddressToString( g_LocalAddress )); // If hosting, update the server GUI. if( NETWORK_GetState() == NETSTATE_SERVER ) SERVERCONSOLE_UpdateIP( g_LocalAddress ); // [BB] Initialize the checksum of the non-map lumps that need to be authenticated when connecting a new player. std::vector<std::string> lumpsToAuthenticate; std::vector<LumpAuthenticationMode> lumpsToAuthenticateMode; lumpsToAuthenticate.push_back( "COLORMAP" ); lumpsToAuthenticateMode.push_back( LAST_LUMP ); lumpsToAuthenticate.push_back( "PLAYPAL" ); lumpsToAuthenticateMode.push_back( LAST_LUMP ); lumpsToAuthenticate.push_back( "HTICDEFS" ); lumpsToAuthenticateMode.push_back( ALL_LUMPS ); lumpsToAuthenticate.push_back( "HEXNDEFS" ); lumpsToAuthenticateMode.push_back( ALL_LUMPS ); lumpsToAuthenticate.push_back( "STRFDEFS" ); lumpsToAuthenticateMode.push_back( ALL_LUMPS ); lumpsToAuthenticate.push_back( "DOOMDEFS" ); lumpsToAuthenticateMode.push_back( ALL_LUMPS ); lumpsToAuthenticate.push_back( "GLDEFS" ); lumpsToAuthenticateMode.push_back( ALL_LUMPS ); lumpsToAuthenticate.push_back( "DECORATE" ); lumpsToAuthenticateMode.push_back( ALL_LUMPS ); lumpsToAuthenticate.push_back( "LOADACS" ); lumpsToAuthenticateMode.push_back( ALL_LUMPS ); lumpsToAuthenticate.push_back( "DEHACKED" ); lumpsToAuthenticateMode.push_back( ALL_LUMPS ); lumpsToAuthenticate.push_back( "GAMEMODE" ); lumpsToAuthenticateMode.push_back( ALL_LUMPS ); FString checksum, longChecksum; bool noProtectedLumpsAutoloaded = true; // [BB] All precompiled ACS libraries need to be authenticated. The only way to find all of them // at this point is to parse all LOADACS lumps. { int lump, lastlump = 0; while ((lump = Wads.FindLump ("LOADACS", &lastlump)) != -1) { FScanner sc(lump); while (sc.GetString()) { NETWORK_AddLumpForAuthentication ( Wads.CheckNumForName (sc.String, ns_acslibrary) ); } } } // [BB] First check the lumps that were marked for authentication while initializing. This // includes for example those lumps included by DECORATE lumps. It's much easier to mark those // lumps while the engine parses the DECORATE code than trying to find all included lumps from // the DECORATE lumps directly. for ( unsigned int i = 0; i < g_LumpNumsToAuthenticate.Size(); ++i ) { if ( !network_GenerateLumpMD5HashAndWarnIfNeeded( g_LumpNumsToAuthenticate[i], Wads.GetLumpFullName (g_LumpNumsToAuthenticate[i]), checksum ) ) noProtectedLumpsAutoloaded = false; longChecksum += checksum; } for ( unsigned int i = 0; i < lumpsToAuthenticate.size(); i++ ) { switch ( lumpsToAuthenticateMode[i] ){ case LAST_LUMP: int lump; lump = Wads.CheckNumForName(lumpsToAuthenticate[i].c_str()); // [BB] Possibly we find the COLORMAP lump only in the colormaps name space. if ( ( lump == -1 ) && ( lumpsToAuthenticate[i].compare ( "COLORMAP" ) == 0 ) ) lump = Wads.CheckNumForName("COLORMAP", ns_colormaps); if ( lump == -1 ) { Printf ( PRINT_BOLD, "Warning: Can't find lump %s for authentication!\n", lumpsToAuthenticate[i].c_str() ); continue; } if ( !network_GenerateLumpMD5HashAndWarnIfNeeded( lump, lumpsToAuthenticate[i].c_str(), checksum ) ) noProtectedLumpsAutoloaded = false; // [BB] To make Doom and Freedoom network compatible, substitue the Freedoom PLAYPAL/COLORMAP hash // by the corresponding Doom hash. // 4804c7f34b5285c334a7913dd98fae16 Doom PLAYPAL hash // 061a4c0f80aa8029f2c1bc12dc2e261e Doom COLORMAP hash // 2e01ae6258f2a0fdad32125537efe1af Freedoom PLAYPAL hash // bb535e66cae508e3833a5d2de974267b Freedoom COLORMAP hash if ( ( stricmp ( lumpsToAuthenticate[i].c_str(), "PLAYPAL" ) == 0 ) && ( stricmp ( checksum.GetChars(), "2e01ae6258f2a0fdad32125537efe1af" ) == 0 ) ) checksum = "4804c7f34b5285c334a7913dd98fae16"; else if ( ( stricmp ( lumpsToAuthenticate[i].c_str(), "COLORMAP" ) == 0 ) && ( stricmp ( checksum.GetChars(), "bb535e66cae508e3833a5d2de974267b" ) == 0 ) ) checksum = "061a4c0f80aa8029f2c1bc12dc2e261e"; longChecksum += checksum; break; case ALL_LUMPS: int workingLump, lastLump; lastLump = 0; while ((workingLump = Wads.FindLump(lumpsToAuthenticate[i].c_str(), &lastLump)) != -1) { if ( !network_GenerateLumpMD5HashAndWarnIfNeeded( workingLump, lumpsToAuthenticate[i].c_str(), checksum ) ) noProtectedLumpsAutoloaded = false; longChecksum += checksum; } break; } } CMD5Checksum::GetMD5( reinterpret_cast<const BYTE *>(longChecksum.GetChars()), longChecksum.Len(), g_lumpsAuthenticationChecksum ); // [BB] Warn the user about problematic auto-loaded files. if ( noProtectedLumpsAutoloaded == false ) { Printf ( PRINT_BOLD, "Warning: Above auto-loaded files contain protected lumps.\n" ); if ( Args->CheckParm( "-host" ) ) Printf ( PRINT_BOLD, "Clients without these files can't connect to this server.\n" ); else Printf ( PRINT_BOLD, "You can't connect to servers without these files.\n" ); } // [BB] Initialize the actor network class indices. for ( unsigned int i = 0; i < PClass::m_Types.Size(); i++ ) { PClass* cls = PClass::m_Types[i]; if ( (cls->IsDescendantOf(RUNTIME_CLASS(AActor))) // [BB] The server only binaries don't know DynamicLight and derived classes. && !(cls->IsDescendantOf(PClass::FindClass("DynamicLight"))) ) cls->ActorNetworkIndex = 1 + g_ActorNetworkIndexClassPointerMap.Push ( cls ); else cls->ActorNetworkIndex = 0; } // [RC/BB] Init the list of PWADs. network_InitPWADList( ); // Call NETWORK_Destruct() when Skulltag closes. atterm( NETWORK_Destruct ); Printf( "UDP Initialized.\n" ); }
//========================================================================== // // Starts a new actor definition // //========================================================================== FActorInfo *CreateNewActor(const FScriptPosition &sc, FName typeName, FName parentName, bool native) { const PClass *replacee = NULL; PClass *ti = NULL; FActorInfo *info = NULL; PClass *parent = RUNTIME_CLASS(AActor); if (parentName != NAME_None) { parent = const_cast<PClass *> (PClass::FindClass (parentName)); const PClass *p = parent; while (p != NULL) { if (p->TypeName == typeName) { sc.Message(MSG_ERROR, "'%s' inherits from a class with the same name", typeName.GetChars()); break; } p = p->ParentClass; } if (parent == NULL) { sc.Message(MSG_ERROR, "Parent type '%s' not found in %s", parentName.GetChars(), typeName.GetChars()); parent = RUNTIME_CLASS(AActor); } else if (!parent->IsDescendantOf(RUNTIME_CLASS(AActor))) { sc.Message(MSG_ERROR, "Parent type '%s' is not an actor in %s", parentName.GetChars(), typeName.GetChars()); parent = RUNTIME_CLASS(AActor); } else if (parent->ActorInfo == NULL) { sc.Message(MSG_ERROR, "uninitialized parent type '%s' in %s", parentName.GetChars(), typeName.GetChars()); parent = RUNTIME_CLASS(AActor); } } if (native) { ti = (PClass*)PClass::FindClass(typeName); if (ti == NULL) { sc.Message(MSG_ERROR, "Unknown native class '%s'", typeName.GetChars()); goto create; } else if (ti != RUNTIME_CLASS(AActor) && ti->ParentClass->NativeClass() != parent->NativeClass()) { sc.Message(MSG_ERROR, "Native class '%s' does not inherit from '%s'", typeName.GetChars(), parentName.GetChars()); parent = RUNTIME_CLASS(AActor); goto create; } else if (ti->ActorInfo != NULL) { sc.Message(MSG_ERROR, "Redefinition of internal class '%s'", typeName.GetChars()); goto create; } ti->InitializeActorInfo(); info = ti->ActorInfo; } else { create: ti = parent->CreateDerivedClass (typeName, parent->Size); info = ti->ActorInfo; } // Copy class lists from parent info->ForbiddenToPlayerClass = parent->ActorInfo->ForbiddenToPlayerClass; info->RestrictedToPlayerClass = parent->ActorInfo->RestrictedToPlayerClass; info->VisibleToPlayerClass = parent->ActorInfo->VisibleToPlayerClass; if (parent->ActorInfo->DamageFactors != NULL) { // copy damage factors from parent info->DamageFactors = new DmgFactors; *info->DamageFactors = *parent->ActorInfo->DamageFactors; } if (parent->ActorInfo->PainChances != NULL) { // copy pain chances from parent info->PainChances = new PainChanceList; *info->PainChances = *parent->ActorInfo->PainChances; } if (parent->ActorInfo->ColorSets != NULL) { // copy color sets from parent info->ColorSets = new FPlayerColorSetMap; *info->ColorSets = *parent->ActorInfo->ColorSets; } info->Replacee = info->Replacement = NULL; info->DoomEdNum = -1; return info; }
void HUD_InitHud() { switch (gameinfo.gametype) { case GAME_Heretic: case GAME_Hexen: healthpic = TexMan.FindTexture("ARTIPTN2"); HudFont=FFont::FindFont("HUDFONT_RAVEN"); break; case GAME_Strife: healthpic = TexMan.FindTexture("I_MDKT"); HudFont=BigFont; // Strife doesn't have anything nice so use the standard font break; default: healthpic = TexMan.FindTexture("MEDIA0"); berserkpic = TexMan.FindTexture("PSTRA0"); HudFont=FFont::FindFont("HUDFONT_DOOM"); break; } IndexFont = V_GetFont("INDEXFONT"); if (HudFont == NULL) HudFont = BigFont; if (IndexFont == NULL) IndexFont = ConFont; // Emergency fallback invgems[0] = TexMan.FindTexture("INVGEML1"); invgems[1] = TexMan.FindTexture("INVGEML2"); invgems[2] = TexMan.FindTexture("INVGEMR1"); invgems[3] = TexMan.FindTexture("INVGEMR2"); fragpic = TexMan.FindTexture("HU_FRAGS"); // Sadly, I don't have anything usable for this. :( KeyTypes.Clear(); UnassignedKeyTypes.Clear(); statspace = SmallFont->StringWidth("Ac:"); // Now read custom icon overrides int lump, lastlump = 0; while ((lump = Wads.FindLump ("ALTHUDCF", &lastlump)) != -1) { FScanner sc(lump); while (sc.GetString()) { if (sc.Compare("Health")) { sc.MustGetString(); FTextureID tex = TexMan.CheckForTexture(sc.String, FTexture::TEX_MiscPatch); if (tex.isValid()) healthpic = TexMan[tex]; } else if (sc.Compare("Berserk")) { sc.MustGetString(); FTextureID tex = TexMan.CheckForTexture(sc.String, FTexture::TEX_MiscPatch); if (tex.isValid()) berserkpic = TexMan[tex]; } else { PClass *ti = PClass::FindClass(sc.String); if (!ti) { Printf("Unknown item class '%s' in ALTHUDCF\n", sc.String); } else if (!ti->IsDescendantOf(RUNTIME_CLASS(AInventory))) { Printf("Invalid item class '%s' in ALTHUDCF\n", sc.String); ti=NULL; } sc.MustGetString(); FTextureID tex; if (!sc.Compare("0") && !sc.Compare("NULL") && !sc.Compare("")) { tex = TexMan.CheckForTexture(sc.String, FTexture::TEX_MiscPatch); } else tex.SetInvalid(); if (ti) SetHUDIcon(static_cast<PClassInventory*>(ti), tex); } } } }
void UCContext::compile(PExpr ex, int flags) { static Label l1(this),l2(this); int tcode,ttype,opcode,op = ex->op(); PExpr e1 = ex->arg1(), e2 = ex->arg2(); Type t = ex->type(); //t.strip_qualifiers(); opcode = equiv_op[op]; if (opcode) { // the type of an operator usually tells us what code to emit // except in the case of relational ops! if (t.is_bool()) t = e1->type(); // *fix 0.9.3 -- ptr check missing! if (t.is_double() && ! t.is_pointer()) opcode = float_equiv[opcode]; compile(e1); if (e2) compile(e2); emit(opcode,NONE,0); return; } tcode = size_code(t); // at this point we can remove any non-trival typecast... if (passthrough_conversion(t,e1)) e1 = e1->arg1(); switch(op) { case ARRAY: { bool is_entry = e1->is_entry(); int array_size = is_entry ? Parser::array_size(e1->entry()) : 0; if (t.is_pointer()) { t.decr_pointer(); tcode = size_code(t); } compile(e2); // put index on stack // *add 1.2.5 Check for array bounds, if requested if (Parser::debug.range_check && array_size > 1) { emit_push_int(array_size); emit(CALLN,DIRECT,Builtin::range_check_function()); } if (t.is_class()) { int sz = t.size(); if (sz > sizeof(double)) { emit_push_int(sz); emit(MUL); // TOS will be index*sizeof(T) compile(e1); // will give us the addr emit(ADD); break; } else { if (sz == 4) tcode = 2; else tcode = 3; } } if (is_entry) { if (array_size > 1) emit(ADDCC + tcode,e1); else emit(ADDPC + tcode,e1); } else { compile(e1); if (tcode==0) emit(ADD); else emit(ADDSW+tcode-1); } } break; case DOT: push_object_ptr(this,e1); compile(e2,flags); emit(DOS); break; case CCONTEXT: // constructor call, w/ or w/out object disposal { Function *pf = e2->function(); PClass pc = pf->class_context(); compile_function_call(this,FUNCTION,flags,e2,true,e1,pc->has_VMT() ? -1 : 0); // *fix 1.0.0 Any temporaries must be unwound before pushing obj on ODS // (only if we are a plain auto var) if (t==t_void) Parser::check_temp_context(); // *fix 1.2.0L allow for override (needed for GCC imports) if (Parser::temp_context()->no_auto_dtor() ) emit(DOS); else { if (e1->is_entry()) { PEntry pe = e1->entry(); if (pc->destructor() == NULL && ! pc->has_VMT()) emit(DOS); else { // Local 'auto' objects get pushed onto the ODS; // *add 1.2.3 Put statically created objects in the static ODL (Object Destructor List) bool is_auto = pe->is_stack_relative(); bool is_direct = pe->is_direct(); if (! is_auto && ! is_direct) emit(DOS); else if (is_auto) { // *fix 1.2.3 Only set the first object if it _will_ be on the ODS Expressions::set_first_object(e1); // set as the first object on the stack frame emit_data_instruction(TOSD,(ulong)pc); } else { // if (is_direct) // *change 1.2.9 The static ODS has been retired; instead, we keep // program and global ODLs which are evaluated at program close and // session close respectively. if (pc->destructor()) LoadedModuleList::ODL_add(pe->global_ptr(),pc->destructor()); } } } else emit(TOSX); } } break; case FCONTEXT: // function returning an object requiring destruction // *change 1.0.0 We use TPODS instruction before functions returning objects... push_object_ptr(this, e1); Expressions::set_first_object(e1); // set as the first object on the stack frame emit_data_instruction(TPODS,(ulong)t.as_class()); break; case DCONTEXT: // dynamic scalar ctor or dtor call. { Function *pf = e1->function(); PClass pc = pf->class_context(); int icb = (pc->has_VMT() && pf->is_constructor()) ? -1 : 0; compile_function_call(this,METHOD_CALL,flags,e1,true,NULL,icb,true); emit(TOSX); } break; case VCONTEXT: // vector ctor or dtor; static if we're passed an array entry { Function *pf = e2->function(); int arr_sz; PEntry pe; if (e1) { pe = e1->entry(); arr_sz = Parser::array_size(pe); } else arr_sz = 0; bool is_dynamic = arr_sz == 0; // *change 1.2.9 For each object in the _static_ array, add to the ODL; // The vector ctor instruction no longer pushes the ODS for static objects. if (! is_dynamic && pe->is_direct()) { PClass pc = pf->class_context(); if (pc->destructor()) { char* ptr = (char*)pe->global_ptr(); int tsz = pe->type.size(); for (int i = 0; i < arr_sz; i++) { LoadedModuleList::ODL_add(ptr,pc->destructor()); ptr += tsz; } } } int icb = ConstructBlock::make(e1,arr_sz,is_dynamic,pf->fun_block()); compile_function_call(this,FUNCTION,flags,e2,true,e1,icb,is_dynamic); } break; case PASS_BY_VALUE: { // needed to match MSVC object model int sz = t.size(); emit(STALC,NONE,sz/sizeof(int)); // allocate on stack (pushes object stack!) compile(e1); // construct object emit(DOS); // pop OS // *fix 1.2.0 There was code to reverse stuff on stack, but the UC stack now grows // downwards, like most processor stacks. This stuff has been broken since 1.1.0!! } break; case ADDR: compile(e1,AS_PTR); break; case DEREF: // Special case: dereferencing a pointer to an object // *fix 0.9.7 left stack droppings because we didn't use flags (DROP!) // *hack 0.9.8 AS_PTR case is different. Surely there is some pattern here? // *hack 1.1.2 Being on the RHS of a reference init. is now explicit! if (flags & AS_PTR) { if (! (flags & AS_REF) && t.is_class() && !t.is_pointer() && !t.is_plain_reference()) compile(e1,flags); else compile(e1); } else { if (t.is_class() && !t.is_pointer()) compile(e1,flags); else { compile(e1); // Special case: a function ptr if (t.is_function()) break; emit_reference(NULL,flags,tcode); } } break; case IREF: // objects and arrays produce references t = ex->entry()->type; // redundant?? if (t.is_object() || Parser::array_size(ex->entry()) > 1) emit( PEA, ex); else { if (t.is_reference()) tcode = POINTER_SZ; // *fix 0.9.7 deref. double references emit_reference(ex,flags,tcode); } break; case ASSIGN: if (!e1) { // special case when ref is already on stack! emit(DUP); // dup the pointer compile(e2); // compile expr emit(is_double_number(e2->type()) ? SWAPD : SWAP); // so ptr is TOS emit_reference(NULL,LVALUE,tcode); } else { // *fix 1.2.0 Assignments were not coded correctly in lvalue situations (e.g 'int& ri = (i = 10)') bool do_push = !(flags & DROP_VALUE), as_ref = (flags & AS_REF); compile(e2); if (do_push & ! as_ref) emit_stack_op(DUP,e2->type()); compile(e1,LVALUE); if (do_push & as_ref) compile(e1,AS_PTR); } break; case INCR: case DECR: case INCR_PTR: case DECR_PTR: // opcode = 0; if (t.is_pointer()) { t.decr_pointer(); ttype = size_code(t); } else ttype = tcode; if (e1->is_entry()) { Type at = e1->entry()->type; if (at.is_class()) { int sz = t.size(); if (sz == sizeof(int)) ttype = 2; else if (sz == sizeof(double)) ttype = 3; else ttype = -1; } if (ttype != -1) { if (!(at.is_ref_or_ptr() && (op==INCR || op==DECR))) opcode = choose(op,INCR,INCC,DECR,DECC,INCR_PTR,INCPC,DECR_PTR,DECPC,0); } else { // ptr to struct!! Encode p = p + sizeof(T) if (e2!=NULL) emit_reference(e1,0,2); // postfix emit_reference(e1,0,2); emit_push_int(t.size()); emit(op==INCR_PTR ? ADD : SUB); if(e2==NULL) emit(DUP); // prefix emit_reference(e1,LVALUE,2); break; } } if (opcode == 0) { opcode = (op==INCR || op==INCR_PTR) ? INCSC : DECSC; compile(e1,AS_PTR); // forced to yield a reference if (!(flags & DROP_VALUE)) emit(DUP); // dup if we're pushing value e1 = NULL; // force stack-relative push/pop! } if (e2==NULL) emit(opcode + ttype, e1); // prefix if (!(flags & DROP_VALUE)) { emit_reference(e1,flags,tcode); // w/ postfix, must keep the reference on TOS! if (e2!=NULL && e1==NULL) emit(SWAP,NONE,0); } if (e2!=NULL) emit(opcode + ttype, e1); // postfix break; case FUNCTION: case DCALL: case EXPR: case METHOD_CALL: case EXPR_METHOD: compile_function_call(this,op,flags,ex); break; case BCAST: compile(e1); op = builtin_conversion(t,e1->type()); if (op) emit(op); break; case LOG_OR: case LOG_AND: { Label l1(this); compile(e1); jump(op==LOG_OR ? JNZND : JZND,&l1); compile(e2); Parser::check_temp_context(); // *fix 0.9.6 NB to do this _before_ any jumps l1.here(); } break; case ARITH_IF: { Label l1(this),l2(this); compile(e1); jump(JZ,&l1); compile(e2->arg1(),flags); jump(JMP,&l2); l1.here(); compile(e2->arg2(),flags); l2.here(); } break; case COMMA: case APPEND: compile(e1,op == COMMA ? DROP_VALUE : 0); compile(e2,flags); break; case COPY_BLOCK: compile(e1); if (!(flags & DROP_VALUE)) emit(DUP); compile(e2); emit(COPY,NONE,e1->type().size()); break; case INIT_REF: // *hack 1.1.2 Make reference init. case more explicit! (see DEREF) compile(e2,AS_PTR | AS_REF); compile(e1,LVALUE); break; case DYNACAST: compile(e1); emit_dynamic_cast(t); break; case REF_STUB: // make a reference out of a non-reference (not needed for constants) compile(e1); // put expression on stack compile(e2,LVALUE); // pop into temp variable compile(e2,AS_PTR); // push addr of temp break; default: cerr << "Unrecognized opcode: " << op << endl; //throw string("compile failed"); break; } }
// Create a new class based on an existing class PClass *PClass::CreateDerivedClass (FName name, unsigned int size) { assert (size >= Size); PClass *type; bool notnew; const PClass *existclass = FindClass(name); // This is a placeholder so fill it in if (existclass != NULL && existclass->Size == (unsigned)-1) { type = const_cast<PClass*>(existclass); if (!IsDescendantOf(type->ParentClass)) { I_Error("%s must inherit from %s but doesn't.", name.GetChars(), type->ParentClass->TypeName.GetChars()); } DPrintf("Defining placeholder class %s\n", name.GetChars()); notnew = true; } else { type = new PClass; notnew = false; } type->TypeName = name; type->ParentClass = this; type->Size = size; type->Pointers = NULL; type->ConstructNative = ConstructNative; if (!notnew) { type->ClassIndex = m_Types.Push (type); } type->Meta = Meta; // Set up default instance of the new class. type->Defaults = new BYTE[size]; memcpy (type->Defaults, Defaults, Size); if (size > Size) { memset (type->Defaults + Size, 0, size - Size); } type->FlatPointers = NULL; type->bRuntimeClass = true; type->ActorInfo = NULL; type->Symbols.SetParentTable (&this->Symbols); if (!notnew) type->InsertIntoHash(); // If this class has an actor info, then any classes derived from it // also need an actor info. if (this->ActorInfo != NULL) { FActorInfo *info = type->ActorInfo = new FActorInfo; info->Class = type; info->GameFilter = GAME_Any; info->SpawnID = 0; info->DoomEdNum = -1; info->OwnedStates = NULL; info->NumOwnedStates = 0; info->Replacement = NULL; info->Replacee = NULL; info->StateList = NULL; info->DamageFactors = NULL; info->PainChances = NULL; m_RuntimeActors.Push (type); } return type; }
FState *FStateDefinitions::ResolveGotoLabel (AActor *actor, PClassActor *mytype, char *name) { PClassActor *type = mytype; FState *state; char *namestart = name; char *label, *offset, *pt; int v; // Check for classname if ((pt = strstr (name, "::")) != NULL) { const char *classname = name; *pt = '\0'; name = pt + 2; // The classname may either be "Super" to identify this class's immediate // superclass, or it may be the name of any class that this one derives from. if (stricmp (classname, "Super") == 0) { type = dyn_cast<PClassActor>(type->ParentClass); actor = GetDefaultByType(type); } else { // first check whether a state of the desired name exists PClass *stype = PClass::FindClass (classname); if (stype == NULL) { I_Error ("%s is an unknown class.", classname); } if (!stype->IsDescendantOf (RUNTIME_CLASS(AActor))) { I_Error ("%s is not an actor class, so it has no states.", stype->TypeName.GetChars()); } if (!stype->IsAncestorOf (type)) { I_Error ("%s is not derived from %s so cannot access its states.", type->TypeName.GetChars(), stype->TypeName.GetChars()); } if (type != stype) { type = static_cast<PClassActor *>(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; // Get the state's address. if (type == mytype) { state = FindState (label); } else { state = type->FindStateByString(label, true); } if (state != NULL) { state += v; } else if (v != 0) { I_Error ("Attempt to get invalid state %s from actor %s.", label, type->TypeName.GetChars()); } else { Printf (TEXTCOLOR_RED "Attempt to get invalid state %s from actor %s.\n", label, type->TypeName.GetChars()); } delete[] namestart; // free the allocated string buffer return state; }