//-------------------------------------------------------------------------- void C2DMap::BuildMapTables(void) { mapalephs.RemoveAll(); SMapAleph *pmapaleph; if (igcmap == NULL) return; POSITION pos = igcmap->cl_alephs.GetHeadPosition(); for (int i=0;i < igcmap->cl_alephs.GetCount();i++) { CIGCAleph *paleph; paleph = &(igcmap->cl_alephs.GetNext(pos)); if (!KnownAleph(paleph)) { pmapaleph = new SMapAleph; pmapaleph->aleph1 = paleph; pmapaleph->sect1 = FindSector(paleph); pmapaleph->aleph2 = FindConnectingAleph(paleph); pmapaleph->sect2 = FindSector(pmapaleph->aleph2); mapalephs.AddTail(*pmapaleph); } } Rescale(); }
EID EntityManager::CreateNPC(psCharacter *chardata, bool updateProxList, bool alwaysWatching) { csVector3 pos; float yrot; psSectorInfo *sectorinfo; iSector *sector; InstanceID instance; chardata->GetLocationInWorld(instance, sectorinfo,pos.x,pos.y,pos.z,yrot); sector = FindSector(sectorinfo->name); if (sector == NULL) { Error3("Could not resolve sector >%s< for NPC %s.", sectorinfo->name.GetData(), ShowID(chardata->GetPID())); delete chardata; return false; } return CreateNPC(chardata, instance, pos, sector, yrot, updateProxList, alwaysWatching); }
bool EntityManager::CreateActionLocation(psActionLocation *al, bool transient = false) { const csVector3 pos = al->GetPosition(); iSector *sector = FindSector(al->GetSectorName()); if (!sector) { CPrintf(CON_ERROR, "Action Location ID %u : Sector not found!\n", al->id); return false; } gemActionLocation *obj = new gemActionLocation(al, sector, 0); // Add action location to all nearby clients obj->UpdateProxList( true ); // Add action location to all Super Clients psserver->npcmanager->AddEntity(obj); //Debug3(LOG_STARTUP ,0, "Action Location ID %u : Created successfully(EID: %u)!", instance->id,obj->GetEID()); return true; }
gemItem* EntityManager::CreateItem(psItem *& iteminstance, bool transient) { psSectorInfo *sectorinfo; csVector3 newpos; float xrot; float yrot; float zrot; iSector *isec; InstanceID instance; iteminstance->GetLocationInWorld(instance, §orinfo,newpos.x,newpos.y,newpos.z,yrot); iteminstance->GetXZRotationInWorld(xrot,zrot); if (sectorinfo==NULL) return NULL; isec = FindSector(sectorinfo->name); if (isec==NULL) return NULL; /* Apparently merchants like to arrange similar items on tables without * them auto-stacking and thus averaging qualities. Similarly, people * like to arrange food on tables, etc. Disabling at the request of Bovek. // Try to stack this first csArray<gemObject*> nearlist = gem->FindNearbyEntities( isec, newpos, RANGE_TO_STACK ); size_t count = nearlist.GetSize(); for (size_t i=0; i<count; i++) { gemObject *nearobj = nearlist[i]; if (!nearobj) continue; psItem *nearitem = nearobj->GetItem(); if ( nearitem && nearitem->CheckStackableWith(iteminstance, false) ) { // Put new item(s) into old stack nearitem->CombineStack(iteminstance); nearitem->Save(false); return nearitem->GetGemObject(); // Done } } */ // Cannot stack, so make a new one // Get the mesh for this object const char *meshname = iteminstance->GetMeshName(); gemItem *obj; if (iteminstance->GetIsContainer()) { obj = new gemContainer(iteminstance,meshname,instance,isec,newpos,xrot,yrot,zrot,0); } else { obj = new gemItem(iteminstance,meshname,instance,isec,newpos,xrot,yrot,zrot,0); } // Won't create item if gemItem entity was not created //CS_ASSERT(obj->GetEntity() != NULL); if (transient && !sectorinfo->GetIsNonTransient()) { // don't create removal events for items in e.g guildhalls iteminstance->ScheduleRemoval(); } obj->Move(newpos,yrot,isec); // Add object to all nearby clients obj->UpdateProxList( true ); // Add object to all Super Clients psserver->npcmanager->AddEntity(obj); return obj; }
bool EntityManager::CreatePlayer (Client* client) { psCharacter *chardata=psServer::CharacterLoader.LoadCharacterData(client->GetPID(),true); if (chardata==NULL) { CPrintf(CON_ERROR, "Couldn't load character for %s!\n", ShowID(client->GetPID())); psserver->RemovePlayer (client->GetClientNum(),"Your character data could not be loaded from the database. Please contact tech support about this."); return false; } // FIXME: This should really be an assert in LoadCharacterData or such psRaceInfo *raceinfo=chardata->GetRaceInfo(); if (raceinfo==NULL) { CPrintf(CON_ERROR, "Character load returned with NULL raceinfo pointer for %s!\n", ShowID(client->GetPID())); psserver->RemovePlayer (client->GetClientNum(),"Your character race could not be loaded from the database. Please contact tech support about this."); delete chardata; return false; } csVector3 pos; float yrot; psSectorInfo *sectorinfo; iSector *sector; InstanceID instance; chardata->GetLocationInWorld(instance,sectorinfo,pos.x,pos.y,pos.z,yrot); sector=FindSector(sectorinfo->name); if (sector==NULL) { Error3("Could not resolve sector >%s< for %s.", sectorinfo->name.GetData(), ShowID(client->GetPID())); psserver->RemovePlayer (client->GetClientNum(),"The server could not create your character entity. (Sector not found) Please contact tech support about this."); delete chardata; return false; } gemActor *actor = new gemActor(chardata,raceinfo->mesh_name, instance,sector,pos,yrot, client->GetClientNum()); client->SetActor(actor); if (!actor || !actor->IsValid() ) { Error2("Error while creating gemActor for Character '%s'\n", chardata->GetCharName()); psserver->RemovePlayer (client->GetClientNum(),"The server could not create your character entity. (new gemActor() failed) Please contact tech support about this."); return false; } chardata->LoadActiveSpells(); // These are commented out now because they are handled by psConnectEvent published // Check for buddy list members // usermanager->NotifyBuddies(client, UserManager::LOGGED_ON); // Check for Guild members to notify // usermanager->NotifyGuildBuddies(client, UserManager::LOGGED_ON); // Set default state actor->SetMode(PSCHARACTER_MODE_PEACE); // Add Player to all Super Clients psserver->npcmanager->AddEntity(actor); psSaveCharEvent *saver = new psSaveCharEvent(actor); saver->QueueEvent(); return true; }
BYTE CDrive::In (WORD wPort_) { BYTE bRet = 0x00; // Continue command execution if we're busy but not transferring data if ((m_sRegs.bStatus & (BUSY|DRQ)) == BUSY) ExecuteNext(); // Register to read from is the bottom 3 bits of the port switch (wPort_ & 0x03) { case regStatus: { // Return value is the status byte bRet = m_sRegs.bStatus; // Type 1 command mode uses more status bits if ((m_sRegs.bCommand & FDC_COMMAND_MASK) <= STEP_OUT_UPD) { // Set the track 0 bit state if (!m_bHeadCyl) { bRet |= TRACK00; m_sRegs.bTrack = 0; // this is updated even in non-update mode! } // The following only apply if there's a disk in the drive if (m_pDisk) { // Set the write protect bit if the disk is read-only if (m_pDisk->IsReadOnly()) bRet |= WRITE_PROTECT; // If spin-up wasn't disabled, flag it complete if (!(m_sRegs.bCommand & CMD_FLAG_SPINUP)) bRet |= SPIN_UP; // Toggle the index pulse status bit periodically to show the disk is spinning static int n = 0; if (IsMotorOn() && !(++n % 1024)) // FIXME: use an event for the correct index timing bRet |= INDEX_PULSE; } } // SAM DICE relies on a strange error condition, which requires special handling else if ((m_sRegs.bCommand & FDC_COMMAND_MASK) == READ_ADDRESS) { static int nBusyTimeout = 0; // Clear busy after 16 polls of the status port if (!(bRet & BUSY)) nBusyTimeout = 0; else if (!(++nBusyTimeout & 0x0f)) { ModifyStatus(0, BUSY); m_bSectorIndex = 0; } } break; } case regTrack: // Return the current track register value (may not match the current physical head position) bRet = m_sRegs.bTrack; TRACE("Disk track: returning %#02x\n", bRet); break; case regSector: // Return the current sector register value bRet = m_sRegs.bSector; // TRACE("Disk sector: returning %#02x\n", byte); break; case regData: { // Data available? if (m_uBuffer) { // Read the next byte into the data register m_sRegs.bData = *m_pbBuffer++; m_uBuffer--; // Has all the data been read? if (!m_uBuffer) { // Reset BUSY and DRQ to show we're done ModifyStatus(0, BUSY|DRQ); // Some commands require additional handling switch (m_sRegs.bCommand & FDC_COMMAND_MASK) { case READ_ADDRESS: break; case READ_TRACK: // No more data available ModifyStatus(RECORD_NOT_FOUND, 0); break; case READ_1SECTOR: // Set the data read status to include data CRC errors ModifyStatus(m_bDataStatus, 0); break; case READ_MSECTOR: // Set the data read status to include data CRC errors, and only continue if ok ModifyStatus(m_bDataStatus, 0); if (!m_bDataStatus) { IDFIELD id; // Advance the sector number m_sRegs.bSector++; // Are there any more sectors to return? if (FindSector(&id)) { TRACE("FDC: Multiple-sector read moving to sector %d\n", id.bSector); // Read the data, reporting anything but CRC errors now m_bDataStatus = ReadSector(m_pbBuffer = m_abBuffer, &m_uBuffer); ModifyReadStatus(); } } break; default: TRACE("Data requested for unknown command (%d)!\n", m_sRegs.bCommand); } } } // Return the data register value bRet = m_sRegs.bData; } } return bRet; }
void CDrive::ExecuteNext () { BYTE bStatus = m_sRegs.bStatus; // Nothing to do if there's no disk in the drive if (!m_pDisk) return; // Continue processing the background if (m_pDisk->IsBusy(&bStatus)) { // Keep the drive motor on as we're busy ModifyStatus(MOTOR_ON, 0); return; } // Some commands require additional handling switch (m_sRegs.bCommand & FDC_COMMAND_MASK) { case READ_1SECTOR: case READ_MSECTOR: { IDFIELD id; if (!FindSector(&id)) ModifyStatus(RECORD_NOT_FOUND, BUSY); else { // Read the data, reporting anything but CRC errors now, as we can't check the CRC until we reach it at the end of the data on the disk m_bDataStatus = ReadSector(m_pbBuffer = m_abBuffer, &m_uBuffer); ModifyReadStatus(); // Just for fun ;-) if (m_sRegs.bTrack == 4 && m_sRegs.bSector == 1 && m_abBuffer[0x016] == 0xC3 && CrcBlock(m_abBuffer, m_uBuffer) == 0x6c54) m_abBuffer[0x016] -= 0x37; } break; } case WRITE_1SECTOR: case WRITE_MSECTOR: { if (m_nState == 0) { IDFIELD id; // Locate the sector, reset busy and signal record not found if we couldn't find it if (!FindSector(&id)) ModifyStatus(RECORD_NOT_FOUND, BUSY); else if (m_pDisk->IsReadOnly()) ModifyStatus(WRITE_PROTECT, BUSY); else { // Prepare data pointer to receive data, and the amount we're expecting m_pbBuffer = m_abBuffer; m_uBuffer = 128U << (id.bSize & 3); // Signal that data is now requested for writing ModifyStatus(DRQ, 0); m_nState++; } } else { // Write complete, so set its status and clear busy ModifyStatus(bStatus, BUSY); } break; } case READ_ADDRESS: { // Read an ID field into our general buffer IDFIELD* pId = reinterpret_cast<IDFIELD*>(m_pbBuffer = m_abBuffer); BYTE bReadStatus = ReadAddress(pId); // If successful set up the number of bytes available to read if (!(bReadStatus & TYPE23_ERROR_MASK)) { m_sRegs.bSector = pId->bTrack; m_uBuffer = sizeof(IDFIELD); ModifyStatus(bStatus|DRQ, 0); // Don't clear BUSY yet! } // Set the error status, resetting BUSY so the client sees the error else { ModifyStatus(bStatus, BUSY); m_uBuffer = 0; } break; } case READ_TRACK: { // Prepare a semi-convincing raw track ReadTrack(m_pbBuffer = m_abBuffer, m_uBuffer = sizeof(m_abBuffer)); ModifyStatus(DRQ, 0); break; } case WRITE_TRACK: { ModifyStatus(bStatus, BUSY); break; } } }