Пример #1
0
void SpawnManager::RemoveNPC(gemObject *obj)
{
    Debug2(LOG_SPAWN,0,"RemoveNPC:%s\n",obj->GetName() );

    ServerStatus::mob_deathcount++;

    PID pid = obj->GetPID();

    Notify3(LOG_SPAWN, "Sending NPC %s disconnect msg to %zu clients.\n", ShowID(obj->GetEID()), obj->GetMulticastClients().GetSize());

    if (obj->GetCharacterData()==NULL)
    {
        Error2("Character data for npc character %s was not found! Entity stays dead.\n", ShowID(pid));
        return;
    }

    SpawnRule *respawn = NULL;
    int spawnruleid = obj->GetCharacterData()->NPC_GetSpawnRuleID();

    if (spawnruleid)
    {
        // Queue for respawn according to rules
        respawn = rules.Get(spawnruleid, NULL);
    }

    if (!respawn)
    {
        if (spawnruleid == 0) // spawnruleid 0 is for non-respawning NPCs
        {
            Notify2(LOG_SPAWN,"Temporary NPC based on player ID %s has died. Entity stays dead.\n", ShowID(pid));
        }
        else
        {
            Error3("Respawn rule for player %s, rule %d was not found! Entity stays dead.\n", ShowID(pid), spawnruleid);
        }

        // Remove mesh, etc from engine
        entityManager->RemoveActor(obj);
        return;
    }

    // Remove mesh, etc from engine
    entityManager->RemoveActor(obj);

    int delay = respawn->GetRespawnDelay();
    PID newplayer = respawn->CheckSubstitution(pid);

    psRespawnGameEvent *newevent = new psRespawnGameEvent(this, delay, newplayer, respawn);
    psserver->GetEventManager()->Push(newevent);

    Notify3(LOG_SPAWN, "Scheduled NPC %s to be respawned in %.1f seconds", ShowID(newplayer), (float)delay/1000.0);
}
Пример #2
0
TribeNeed* TribeNeedSet::CalculateNeed(NPC * npc)
{
    for (size_t i=0; i < needs.GetSize()-1; i++)
    {
        for (size_t j=i+1; j < needs.GetSize(); j++)
        {
            if (needs[i]->GetNeedValue(npc) < needs[j]->GetNeedValue(npc))
            {
                TribeNeed *tmp = needs[i];
                needs[i] = needs[j];
                needs[j] = tmp;
            }
        }
    }

    csString log;
    log.Format("Need for %s(%s)",npc->GetName(),ShowID(npc->GetEID()));
    for (size_t i=0; i < needs.GetSize(); i++)
    {
        log.AppendFmt("\n%20s %10.2f -> %s",needs[i]->GetTypeAndName().GetDataSafe(),needs[i]->current_need,needs[i]->GetNeed()->GetTypeAndName().GetDataSafe());
    }
    Debug2(LOG_TRIBES, GetTribe()->GetID(), "%s", log.GetData());

    needs[0]->ResetNeed();
    return needs[0];
}
Пример #3
0
void psClientDR::HandleDeadReckon( MsgEntry* me )
{
    psDRMessage drmsg(me,0,msgstrings,psengine->GetEngine() );
    GEMClientActor* gemActor = (GEMClientActor*)celclient->FindObject( drmsg.entityid );
     
    if (!gemActor)
    {
        csTicks currenttime = csGetTicks();
        if (currenttime - lastquery > 750)
        {
            lastquery = currenttime;
        }

        Error2("Got DR message for unknown entity %s.", ShowID(drmsg.entityid));
        return;
    }

    if (!msgstrings)
    {
        Error1("msgstrings not received, cannot handle DR");
        return;
    }

    // Ignore any updates to the main player...psForcePositionMessage handles that.
    if (gemActor == celclient->GetMainPlayer())
    {
        psengine->GetModeHandler()->SetModeSounds(drmsg.mode);
        return;
    }

    // Set data for this actor
    gemActor->SetDRData(drmsg);
}
Пример #4
0
EID EntityManager::CreateNPC(psCharacter *chardata, InstanceID instance, csVector3 pos, iSector* sector, float yrot,
                             bool updateProxList, bool alwaysWatching)
{
    if (chardata==NULL)
        return false;

    // FIXME: This should be an assert elsewhere.
    psRaceInfo *raceinfo=chardata->GetRaceInfo();
    if (raceinfo==NULL)
    {
        CPrintf(CON_ERROR, "NPC ID %u: Character Load returned with NULL raceinfo pointer!\n", ShowID(chardata->GetPID()));
        delete chardata;
        return false;
    }

    gemNPC *actor = new gemNPC(chardata, raceinfo->mesh_name, instance, sector, pos, yrot, 0);
    actor->SetAlwaysWatching(alwaysWatching);

    if ( !actor->IsValid() )
    {
        CPrintf(CON_ERROR, "Error while creating Entity for NPC '%s'\n", ShowID(chardata->GetPID()));
        delete actor;
        delete chardata;
        return false;
    }

    // This is required to identify all managed npcs.
    actor->SetSuperclientID( chardata->GetAccount() );
    
    // Add NPC Dialog plugin if any knowledge areas are defined in db for him.
    actor->SetupDialog(chardata->GetPID(), true);

    // Setup prox list and send to anyone who needs him
    if ( updateProxList )
    {
        actor->UpdateProxList( true );
    
//        CPrintf(CON_NOTIFY,"------> Entity Manager Setting Imperv\n");
        psserver->npcmanager->ControlNPC( actor );
    }
    Debug3(LOG_NPC, 0, "Created NPC actor: <%s>[%s] in world", actor->GetName(), ShowID(actor->GetEID()));

    return actor->GetEID();
}
Пример #5
0
void psClientDR::HandleStatsUpdate( MsgEntry* me )
{
    psStatDRMessage statdrmsg(me);
    GEMClientActor* gemObject  = (GEMClientActor*)celclient->FindObject( statdrmsg.entityid );
    if (!gemObject)
    {
        Error2("Stat request failed because CelClient not ready for %s", ShowID(statdrmsg.entityid));
        return;
    }

    // Dirty short cut to allways display 0 HP when dead.
    if (!gemObject->IsAlive() && statdrmsg.hp)
    {
//printf("clientdr 275 dead");
        Error1("Server report HP but object is not alive");
        statdrmsg.hp = 0;
        statdrmsg.hp_rate = 0;
    }
    
    // Check if this client actor was updated
    GEMClientActor* mainActor = celclient->GetMainPlayer();
    
    if (mainActor == gemObject)
    {
        gemObject->GetVitalMgr()->HandleDRData(statdrmsg,"Self");
    }        
    else 
    {   // Publish Vitals data using EntityID
        csString ID;
        ID.Append(gemObject->GetEID().Unbox());
        gemObject->GetVitalMgr()->HandleDRData(statdrmsg, ID.GetData() );
    }

    //It is not an else if so Target is always published
    if (psengine->GetCharManager()->GetTarget() == gemObject)
        gemObject->GetVitalMgr()->HandleDRData(statdrmsg,"Target"); 
    
    if (mainActor != gemObject && gemObject->IsGroupedWith(celclient->GetMainPlayer()) )
    {
        if (!groupWindow)
        {
            // Get the windowMgr

            pawsWidget* widget = PawsManager::GetSingleton().FindWidget("GroupWindow");
            groupWindow = (pawsGroupWindow*)widget;

            if (!groupWindow) 
            {
                Error1("Group Window Was Not Found. Bad Error");
                return;
            }
        }
        
        groupWindow->SetStats(gemObject);
    }
}
Пример #6
0
csString psResumeScriptEvent::ToString() const
{
    csString result;
    result.Format("Resuming script operation %s",scriptOp->GetName());
    if (npc)
    {
        result.AppendFmt("for %s (%s)", npc->GetName(), ShowID(npc->GetEID()));
    }
    return result;
}
Пример #7
0
EID EntityManager::CreateNPC(PID npcID, bool updateProxList, bool alwaysWatching)
{
    psCharacter *chardata=psServer::CharacterLoader.LoadCharacterData(npcID,false);
    if (chardata==NULL)
    {
        CPrintf(CON_ERROR, "Couldn't load character for NPC %s.", ShowID(npcID));
        return 0;
    }

    return CreateNPC(chardata, updateProxList, alwaysWatching);
}
Пример #8
0
void Tribe::SendPerception(const char* pcpt, csArray<NPC*> npcs)
{
    Perception perception(pcpt);
    for(size_t i=0; i<npcs.GetSize(); i++)
    {
        NPC* npc = npcs[i];
        RDebug(this, 5, "--> Percept npc %s(%s): %s",npc->GetName(),ShowID(npc->GetEID()),perception.ToString(npc).GetDataSafe());

        npc->TriggerEvent(&perception);
    }
}
Пример #9
0
void EntityManager::HandleUserAction(MsgEntry* me, Client *client)
{
    psUserActionMessage actionMsg(me);
    csString action;

    if (!actionMsg.valid)
    {
        Debug2(LOG_NET,me->clientnum,"Received unparsable psUserActionMessage from client id %u.",me->clientnum);
        return;
    }

    gemObject *object = gem->FindObject(actionMsg.target);

    if (actionMsg.target.IsValid() && !object)
    {
        Debug2(LOG_ANY, me->clientnum, "User action on unknown entity (%s)!", ShowID(actionMsg.target));
        return;
    }

    client->SetTargetObject(object);  // have special tracking for this for fast processing of other messages

    if (!object)
    {
        // TODO: Evaluate if this output is needed. 
        Debug2(LOG_ANY, me->clientnum, "User action on none or unknown object (%s)!", ShowID(actionMsg.target));
        return;
    }

    // Resolve default behaviour
    action = actionMsg.action;
    if (action == "dfltBehavior")
    {
        action = object->GetDefaultBehavior(actionMsg.dfltBehaviors);
        if (action.IsEmpty())
        {
            return;
        }
    }

    if (action == "select" || action == "context")
    {
        if (object != NULL)
            object->SendTargetStatDR(client);
    }

    Debug4(LOG_USER,client->GetClientNum(), "User Action: %s %s %s",client->GetName(),
        (const char *)action,
        (object)?object->GetName():"None")

    object->SendBehaviorMessage(action, client->GetActor() );
}
Пример #10
0
void psDespawnGameEvent::Trigger()
{
    gemObject* object = gem->FindObject(entity);
    if(!object)
    {
        csString status;
        status.Format("Despawn event triggered for non-existant NPC %s!", ShowID(entity));
        psserver->GetLogCSV()->Write(CSV_STATUS, status);

        Error2("%s", status.GetData());
        return;
    }
    spawnmanager->RemoveNPC(object);
}
Пример #11
0
void psClientCharManager::ChangeTrait( MsgEntry* me )
{
    psTraitChangeMessage mesg(me);
    EID objectID = mesg.target;

    GEMClientActor *actor = dynamic_cast<GEMClientActor*>(psengine->GetCelClient()->FindObject(objectID));
    if (!actor)
    {
        Error2("Got trait change for %s, but couldn't find it!", ShowID(objectID));
        return;
    }

    // Update main object
    //psengine->BuildAppearance( object->pcmesh->GetMesh(), mesg.string );
    actor->CharAppearance()->ApplyTraits(mesg.string);

    // Update any doll views registered for changes
    csArray<iPAWSSubscriber*> dolls = PawsManager::GetSingleton().ListSubscribers("sigActorUpdate");
    for (size_t i=0; i<dolls.GetSize(); i++)
    {
        if (dolls[i] == NULL)
            continue;
        pawsObjectView* doll = dynamic_cast<pawsObjectView*>(dolls[i]);

        if (doll == NULL)
            continue;
        if (doll->GetID() == objectID.Unbox()) // This is a doll of the updated object
        {
            iMeshWrapper* dollObject = doll->GetObject();
            if (dollObject == NULL)
            {
                Error2("Cannot update registered doll view with ID %d because it has no object", doll->GetID());
                continue;
            }
            psCharAppearance* p = doll->GetCharApp();
            p->Clone(actor->CharAppearance());
            p->SetMesh(dollObject);
            p->ApplyTraits(mesg.string);
        }
    }
}
Пример #12
0
void SpawnManager::HandleLootItem(MsgEntry *me,Client *client)
{
    psLootItemMessage msg(me);

    // Possible hack here?  We are trusting the client to send the right msg.entity?
    gemObject *object = gem->FindObject(msg.entity);
    if (!object)
    {
        Error3("LootItem Message from %s specified an erroneous entity id: %s.\n", client->GetName(), ShowID(msg.entity));
        return;
    }

    gemActor *obj = object->GetActorPtr();
    if (!obj)
    {
        Error3("LootItem Message from %s specified a non-actor entity id: %s.\n", client->GetName(), ShowID(msg.entity));
        return;
    }
    psCharacter *chr = obj->GetCharacterData();
    if (!chr)
    {
        Error3("LootItem Message from %s specified a non-character entity id: %s.\n", client->GetName(), ShowID(msg.entity));
        return;
    }

    // Check the range to the lootable object.
    if (client->GetActor()->RangeTo(obj) > RANGE_TO_LOOT )
    {
        psserver->SendSystemError(client->GetClientNum(), "Too far away to loot %s.", obj->GetName() );
        return;
    }

    psItem *item = chr->RemoveLootItem(msg.lootitem);
    if (!item)
    {
        // Take this out because it is just the result of duplicate loot commands due to lag
        //Warning3(LOG_COMBAT,"LootItem Message from %s specified bad item id of %d.\n",client->GetName(), msg.lootitem);
        return;
    }

    item->SetLoaded();

    csRef<PlayerGroup> group = client->GetActor()->GetGroup();
    Client *randfriendclient = NULL;
    if (group.IsValid())
    {
        randfriendclient = obj->GetRandomLootClient(RANGE_TO_LOOT*10);
        if (!randfriendclient)
        {
            Error3("GetRandomLootClient failed for loot msg from %s, object %s.\n", client->GetName(), item->GetName() );
            return;
        }
    }

    csString type;
    Client *looterclient;  // Client that gets the item
    if ( msg.lootaction == msg.LOOT_SELF || !group.IsValid() )
    {
        looterclient = client;
        type = "Loot Self";
    }
    else
    {
        looterclient = randfriendclient;
        type = "Loot Roll";
    }

    // Ask group member before take
    if (msg.lootaction == msg.LOOT_SELF && group.IsValid() && client != randfriendclient && obj->HasBeenAttackedBy(randfriendclient->GetActor()))
    {
        psserver->SendSystemInfo(client->GetClientNum(),
                                 "Asking roll winner %s if you may take the %s...",
                                  randfriendclient->GetName(), item->GetName() );
        csString request;
        request.Format("You have won the roll for a %s, but %s wants to take it."
                       "  Will you allow this action?",
                       item->GetName(), client->GetName());

        // Item will be held in the prompt until answered.

        PendingLootPrompt *p = new PendingLootPrompt(client, randfriendclient, item, chr, request, cacheManager, gem);
        psserver->questionmanager->SendQuestion(p);

        type.Append(" Pending");
    }
    // Continue with normal looting if not prompting
    else
    {
        // Create the loot message
        csString lootmsg;
        if (group.IsValid())
            lootmsg.Format("%s won the roll and",looterclient->GetName());
        else
            lootmsg.Format("You");
        lootmsg.AppendFmt(" looted a %s",item->GetName());

        // Attempt to give to looter
        bool dropped = looterclient->GetActor()->GetCharacterData()->Inventory().AddOrDrop(item);

        if (!dropped)
        {
            lootmsg.Append(", but can't hold anymore");
            type.Append(" (dropped)");
        }

        // Send out the loot message
        psSystemMessage loot(me->clientnum, MSG_LOOT, lootmsg.GetData() );
        looterclient->GetActor()->SendGroupMessage(loot.msg);

        item->Save(false);
    }

    // Trigger item removal on every client in the group which has intrest
    if (group.IsValid())
    {
        for (int i=0; i < (int)group->GetMemberCount(); i++)
        {
            int cnum = group->GetMember(i)->GetClientID();
            if (obj->IsLootableClient(cnum))
            {
                psLootRemoveMessage rem(cnum,msg.lootitem);
                rem.SendMessage();
            }
        }
    }
    else
    {
        psLootRemoveMessage rem(client->GetClientNum(),msg.lootitem);
        rem.SendMessage();
    }

    psLootEvent evt(
                   chr->GetPID(),
                   chr->GetCharName(),
                   looterclient->GetCharacterData()->GetPID(),
                   looterclient->GetCharacterData()->GetCharName(),
                   item->GetUID(),
                   item->GetName(),
                   item->GetStackCount(),
                   (int)item->GetCurrentStats()->GetQuality(),
                   0
                   );
    evt.FireEvent();

}
Пример #13
0
void SpawnManager::Respawn(PID playerID, SpawnRule* spawnRule)
{
    psCharacter *chardata=psServer::CharacterLoader.LoadCharacterData(playerID,false);
    if (chardata==NULL)
    {
        Error2("Character %s to be respawned does not have character data to be loaded!\n", ShowID(playerID));
        return;
    }

    csVector3 pos;
    float angle;
    csString sectorName;
    iSector* sector = NULL;
    InstanceID instance;

    int count = 4; // For random positions we try 4 times before going with the result.

    // DetermineSpawnLoc will return true if it is a random picked position so for fixed we will fall true
    // on the first try.
    while (spawnRule->DetermineSpawnLoc(chardata, pos, angle, sectorName, instance) && spawnRule->GetMinSpawnSpacingDistance() > 0.0 && count-- > 0)
    {
        sector = psserver->entitymanager->GetEngine()->GetSectors()->FindByName(sectorName);

        csArray<gemObject*> nearlist = psserver->entitymanager->GetGEM()->FindNearbyEntities(sector, pos, spawnRule->GetMinSpawnSpacingDistance(), false);
        if (nearlist.IsEmpty())
        {
            break; // Nothing in the neare list so spawn position is ok.
        }
        Debug4(LOG_SPAWN,0,"Spawn position %s is occuplied by %zu entities. %s",
               toString(pos,sector).GetDataSafe(),
               nearlist.GetSize(),count>0?" Will Retry":"Last try");

    }

    CS_ASSERT(sector);

    Debug1(LOG_SPAWN,0,"Position accepted");
    Respawn(chardata, instance, pos, angle, sectorName);
}
Пример #14
0
gemNPC* EntityManager::CreateFamiliar (gemActor *owner, PID masterPID)
{
    psCharacter *chardata = owner->GetCharacterData();

    PID familiarID, masterFamiliarID;
    csString familiarname;
    csVector3 pos;
    float yrot = 0.0F;
    iSector *sector;

    // FIXME: This probably ought to be an assertion.
    if ( chardata == NULL )
    {
        CPrintf(CON_ERROR, "Couldn't load character for familiar %s.\n", ShowID(owner->GetPID()));
        return NULL;
    }
    
    masterFamiliarID = masterPID == 0? GetMasterFamiliarID( chardata ) : masterPID;

    // Change Familiar's Name
    const char *charname = chardata->GetCharName();
    if ( charname[strlen(charname)-1] == 's' )
    {
        familiarname.Format("%s'", charname);
    }
    else
    {
        familiarname.Format("%s's", charname);
    }

    // Adjust Position of Familiar from owners pos
    owner->GetPosition( pos, yrot, sector );
    InstanceID instance = owner->GetInstance();

    familiarID = this->CopyNPCFromDatabase( masterFamiliarID, pos.x + 1.5, pos.y, pos.z + 1.5, yrot, sector->QueryObject()->GetName(), instance, familiarname, "Familiar" );
    if ( familiarID == 0 )
    {
        CPrintf(CON_ERROR, "CreateFamiliar failed for %s: Could not copy the master NPC %s\n", ShowID(owner->GetPID()), ShowID(masterFamiliarID));
        psserver->SendSystemError( owner->GetClientID(), "Could not copy the master NPC familiar." );
        return NULL;
    }

    // Create Familiar using new ID
    this->CreateNPC( familiarID , false); //Do not update proxList, we will do that later.

    gemNPC * npc = GEMSupervisor::GetSingleton().FindNPCEntity( familiarID );
    if (npc == NULL)
    {
        psserver->SendSystemError( owner->GetClientID(), "Could not find GEM and set its location.");
        return NULL;
    }

    npc->GetCharacterData()->NPC_SetSpawnRuleID( 0 );
    npc->SetOwner( owner );

    owner->GetClient()->SetFamiliar( npc );
    owner->GetCharacterData()->SetFamiliarID( familiarID );

    db->Command("INSERT INTO npc_knowledge_areas(player_id, area, priority) VALUES (%d, 'Pet %s 1', '1')", familiarID.Unbox(), npc->GetCharacterData()->GetRaceInfo()->name.GetData());

    psServer::CharacterLoader.SaveCharacterData( npc->GetCharacterData(), npc, false );

    psserver->npcmanager->ControlNPC( npc );
    psserver->npcmanager->CreatePetOwnerSession( owner, npc->GetCharacterData() );

    // For now familiars cannot be attacked as they are defenseless
    npc->GetCharacterData()->SetImperviousToAttack( ALWAYS_IMPERVIOUS );

    // Add npc to all nearby clients
    npc->UpdateProxList( true );

    return npc;
}
Пример #15
0
void CharCreationManager::HandleUploadMessage(MsgEntry* me, Client* client)
{
    Debug1(LOG_NEWCHAR, me->clientnum,"New Character is being created");

    psCharUploadMessage upload(me);

    if(!upload.valid)
    {
        Debug2(LOG_NET,me->clientnum,"Received unparsable psUploadMessage from client %u.",me->clientnum);
        return;
    }

    AccountID acctID = client->GetAccountID();
    if(!acctID.IsValid())
    {
        Error2("Player tried to upload a character to unknown account %s.", ShowID(acctID));

        psCharRejectedMessage reject(me->clientnum);

        psserver->GetEventManager()->Broadcast(reject.msg, NetBase::BC_FINALPACKET);
        psserver->RemovePlayer(me->clientnum,"Could not find your account.");
        return;
    }

    // Check to see if the player already has 4 accounts;
    csString query;
    query.Format("SELECT id FROM characters WHERE account_id=%d", acctID.Unbox());
    Result result(db->Select(query));
    if(result.IsValid() && result.Count() >= CHARACTERS_ALLOWED)
    {
        psserver->RemovePlayer(me->clientnum,"At your character limit.");
        return;
    }

    csString playerName =  upload.name;
    csString lastName =  upload.lastname;

    playerName = NormalizeCharacterName(playerName);
    lastName = NormalizeCharacterName(lastName);

    // Check banned names
    if(psserver->GetCharManager()->IsBanned(playerName))
    {
        csString error;
        error.Format("The name %s is banned", playerName.GetData());
        psCharRejectedMessage reject(me->clientnum,
                                     psCharRejectedMessage::RESERVED_NAME,
                                     (char*)error.GetData());
        reject.SendMessage();
        return;
    }

    if(psserver->GetCharManager()->IsBanned(lastName))
    {
        csString error;
        error.Format("The lastname %s is banned", lastName.GetData());
        psCharRejectedMessage reject(me->clientnum,
                                     psCharRejectedMessage::RESERVED_NAME,
                                     (char*)error.GetData());
        reject.SendMessage();
        return;
    }

    Debug3(LOG_NEWCHAR, me->clientnum,"Got player firstname (%s) and lastname (%s)\n",playerName.GetData(), lastName.GetData());

    ///////////////////////////////////////////////////////////////
    //  Check to see if the player name is valid
    ///////////////////////////////////////////////////////////////
    if(playerName.Length() == 0 || !FilterName(playerName))
    {
        psCharRejectedMessage reject(me->clientnum,
                                     psCharRejectedMessage::NON_LEGAL_NAME,
                                     "The name you specifed is not a legal player name.");

        psserver->GetEventManager()->SendMessage(reject.msg);
        return;
    }

    if(lastName.Length() != 0 && !FilterName(lastName))
    {
        psCharRejectedMessage reject(me->clientnum,
                                     psCharRejectedMessage::NON_LEGAL_NAME,
                                     "The name you specifed is not a legal lastname.");

        psserver->GetEventManager()->SendMessage(reject.msg);
        return;
    }

    Debug2(LOG_NEWCHAR, me->clientnum,"Checking player firstname '%s'..\n",playerName.GetData());
    ///////////////////////////////////////////////////////////////
    //  Check to see if the character name is unique in 'characters'.
    ///////////////////////////////////////////////////////////////
    if(!IsUnique(playerName))
    {
        psCharRejectedMessage reject(me->clientnum,
                                     psCharRejectedMessage::NON_UNIQUE_NAME,
                                     "The firstname you specifed is not unique.");

        psserver->GetEventManager()->SendMessage(reject.msg);
        return;
    }

    if(lastName.Length())
    {
        Debug2(LOG_NEWCHAR, me->clientnum,"Checking player lastname '%s'..\n",lastName.GetData());
        if(!IsLastNameAvailable(lastName, acctID))
        {
            psCharRejectedMessage reject(me->clientnum,
                                         psCharRejectedMessage::NON_UNIQUE_NAME,
                                         "The lastname you specifed is not unique.");

            psserver->GetEventManager()->SendMessage(reject.msg);
            return;
        }
    }
    ///////////////////////////////////////////////////////////////
    //  Check to see if the character name is on the reserve list.
    ///////////////////////////////////////////////////////////////
    int reservedName = IsReserved(playerName, acctID);
    if(reservedName == NAME_RESERVED)
    {
        csString error;
        error.Format("The name %s is reserved", playerName.GetData());
        psCharRejectedMessage reject(me->clientnum,
                                     psCharRejectedMessage::RESERVED_NAME,
                                     (char*)error.GetData());

        psserver->GetEventManager()->SendMessage(reject.msg);
        return;
    }


    csString error;
    if(!psserver->charCreationManager->Validate(upload, error))
    {
        error.Append(", your creation choices are invalid.");
        psCharRejectedMessage reject(me->clientnum,
                                     psCharRejectedMessage::INVALID_CREATION,
                                     (char*)error.GetData());

        reject.SendMessage();
        return;
    }

    ///////////////////////////////////////////////////////////////
    //  Create the psCharacter structure for the player.
    ///////////////////////////////////////////////////////////////
    psCharacter* chardata=new psCharacter();
    chardata->SetCharType(PSCHARACTER_TYPE_PLAYER);
    chardata->SetFullName(playerName,lastName);
    chardata->SetCreationInfo(upload.bio);

    psRaceInfo* raceinfo=psserver->GetCacheManager()->GetRaceInfoByNameGender(upload.race, (PSCHARACTER_GENDER)upload.gender);
    if(raceinfo==NULL)
    {
        Error3("Invalid race/gender combination on character creation:  Race='%d' Gender='%d'", upload.race, upload.gender);
        psCharRejectedMessage reject(me->clientnum);
        psserver->GetEventManager()->Broadcast(reject.msg, NetBase::BC_FINALPACKET);
        psserver->RemovePlayer(me->clientnum,"Player tried to create an invalid race/gender.");
        delete chardata;
        return;
    }
    chardata->SetRaceInfo(raceinfo);
    chardata->SetHitPoints(50.0);
    chardata->GetMaxHP().SetBase(0.0);
    chardata->GetMaxMana().SetBase(0.0);

    //range is unused here
    float x,y,z,yrot,range;
    const char* sectorname;
    InstanceID newinstance = DEFAULT_INSTANCE;

    //get the option entries for tutorial from the server options. Note it's tutorial:variousdata
    optionEntry* tutorialEntry = psserver->GetCacheManager()->getOptionSafe("tutorial","");
    sectorname = tutorialEntry->getOptionSafe("sectorname", "tutorial")->getValue();

    psSectorInfo* sectorinfo = psserver->GetCacheManager()->GetSectorInfoByName(sectorname);

    if(!sectorinfo || PlayerHasFinishedTutorial(acctID, sectorinfo->uid))
    {
        raceinfo->GetStartingLocation(x,y,z,yrot,range,sectorname);
        sectorinfo = psserver->GetCacheManager()->GetSectorInfoByName(sectorname);

        //As we aren't going in the tutorial disable the tutorial help messages disable them
        for(int i = 0; i < TutorialManager::TUTOREVENTTYPE_COUNT; i++)
            chardata->CompleteHelpEvent(i);
    }
    else
    {
        // Try tutorial level first.
        x = tutorialEntry->getOptionSafe("sectorx", "-225.37")->getValueAsDouble();
        y = tutorialEntry->getOptionSafe("sectory", "-21.32")->getValueAsDouble();
        z = tutorialEntry->getOptionSafe("sectorz", "26.79")->getValueAsDouble();
        yrot = tutorialEntry->getOptionSafe("sectoryrot", "-2.04")->getValueAsDouble();
    }

    bool sectorFound = true;

    if(sectorinfo && EntityManager::GetSingleton().FindSector(sectorinfo->name) == NULL)
    {
        Error2("Sector='%s' found but no map file was detected for it. Using NPCroom1", sectorname);
        sectorinfo = psserver->GetCacheManager()->GetSectorInfoByName("NPCroom1");
        if(sectorinfo && EntityManager::GetSingleton().FindSector(sectorinfo->name) == NULL)
        {
            Error1("NPCroom1 failed - Critical");
            sectorFound = false;
        }
        else if(sectorinfo && EntityManager::GetSingleton().FindSector(sectorinfo->name))
        {
            sectorFound = true;
        }
        else
        {
            sectorFound = false;
        }
    }
    else if(sectorinfo && EntityManager::GetSingleton().FindSector(sectorinfo->name))
    {
        sectorFound = true;
    }
    else
    {
        sectorFound = false;
    }


    if(!sectorFound)
    {
        Error2("Unresolvable starting sector='%s'", sectorname);
        psCharRejectedMessage reject(me->clientnum);
        psserver->GetEventManager()->Broadcast(reject.msg, NetBase::BC_FINALPACKET);
        psserver->RemovePlayer(me->clientnum,"No starting Sector.");
        delete chardata;
        return;
    }

    chardata->SetLocationInWorld(newinstance, sectorinfo, x, y, z, yrot);

    psTrait* trait;
//    CPrintf(CON_DEBUG, "Trait: %d\n", upload.selectedFace );
    trait = psserver->GetCacheManager()->GetTraitByID(upload.selectedFace);
    if(trait)
        chardata->SetTraitForLocation(trait->location, trait);

    trait = psserver->GetCacheManager()->GetTraitByID(upload.selectedHairStyle);
    if(trait)
        chardata->SetTraitForLocation(trait->location, trait);

    trait = psserver->GetCacheManager()->GetTraitByID(upload.selectedBeardStyle);
    if(trait)
        chardata->SetTraitForLocation(trait->location, trait);

    trait = psserver->GetCacheManager()->GetTraitByID(upload.selectedHairColour);
    if(trait)
        chardata->SetTraitForLocation(trait->location, trait);

    trait = psserver->GetCacheManager()->GetTraitByID(upload.selectedSkinColour);
    if(trait)
        chardata->SetTraitForLocation(trait->location, trait);

    gemActor* actor = new gemActor(gemSupervisor, cacheManager, entityManager, chardata,
                                   raceinfo->mesh_name,
                                   newinstance,
                                   EntityManager::GetSingleton().FindSector(sectorinfo->name),
                                   csVector3(x,y,z),yrot,
                                   client->GetClientNum());

    actor->SetupCharData();

    if(!upload.verify)
    {
        if(!psServer::CharacterLoader.NewCharacterData(acctID,chardata))
        {
            Error1("Character could not be created.");
            psCharRejectedMessage reject(me->clientnum);
            psserver->GetEventManager()->Broadcast(reject.msg, NetBase::BC_FINALPACKET);
            psserver->RemovePlayer(me->clientnum,"Your character could not be created in the database.");
            delete chardata;
            return;
        }
    }

    // Check to see if a path name was set. If so we will use that to generate
    // the character starting stats and skills.
    if(upload.path != "None")
    {
        // Progression Event name is PATH_PathName
        csString name("PATH_");
        name.Append(upload.path);
        ProgressionScript* script = psserver->GetProgressionManager()->FindScript(name.GetData());
        if(script)
        {
            // The script uses the race base character points to calculate starting stats.
            MathEnvironment env;
            env.Define("CharPoints", raceinfo->initialCP);
            env.Define("Actor", actor);
            script->Run(&env);
        }
    }
    else
    {
        //int cpUsage = psserver->charCreationManager->CalculateCPChoice( upload.choices ) +
        //              psserver->charCreationManager->CalculateCPLife(upload.lifeEvents );
        for(size_t ci = 0; ci < upload.choices.GetSize(); ci++)
        {
            CharCreationManager::CreationChoice* choice = psserver->charCreationManager->FindChoice(upload.choices[ci]);
            if(choice)
            {
                csString name(psserver->charCreationManager->FindChoice(upload.choices[ci])->name.GetData());
                Debug3(LOG_NEWCHAR, me->clientnum,"Choice: %s Creation Script: %s", name.GetData(), choice->eventScript.GetData());

                MathEnvironment env;
                env.Define("Actor", actor);
                if(choice->choiceArea == FATHER_JOB || choice->choiceArea == MOTHER_JOB)
                {
                    int modifier = (choice->choiceArea == FATHER_JOB) ? upload.fatherMod : upload.motherMod;
                    if(modifier > 3 || modifier < 1)
                        modifier = 1;

                    env.Define("ParentStatus", modifier);
                }
                ProgressionScript* script = psserver->GetProgressionManager()->FindScript(choice->eventScript);
                if(script)
                    script->Run(&env);
            }
            else
            {
                Debug2(LOG_NEWCHAR, me->clientnum,"Character Choice %d not found\n", upload.choices[ci]);
            }
        }
        for(size_t li = 0; li < upload.lifeEvents.GetSize(); li++)
        {
            MathEnvironment env;
            env.Define("Actor", actor);
            LifeEventChoiceServer* lifeEvent = psserver->charCreationManager->FindLifeEvent(upload.lifeEvents[li]);
            if(!lifeEvent)
            {
                Error2("No LifeEvent Script found: %d", upload.lifeEvents[li]);
                continue;
            }

            csString scriptName(lifeEvent->eventScript.GetData());
            Debug2(LOG_NEWCHAR, me->clientnum, "LifeEvent Script: %s", scriptName.GetDataSafe());

            ProgressionScript* script = psserver->GetProgressionManager()->FindScript(scriptName);
            if(script)
                script->Run(&env);
        }
    }

    if(!upload.verify)
    {

        if(reservedName == NAME_RESERVED_FOR_YOU)
        {
            AssignScript(chardata);
        }
        // This function recalculates the Max HP, Mana and Stamina of the new character
        chardata->RecalculateStats();

        // Make sure the new player have HP, Mana and Samina that was calculated
        chardata->SetHitPoints(chardata->GetMaxHP().Base());
        chardata->SetMana(chardata->GetMaxMana().Base());
        chardata->SetStamina(chardata->GetMaxPStamina().Base(),true);
        chardata->SetStamina(chardata->GetMaxMStamina().Base(),false);


        psServer::CharacterLoader.SaveCharacterData(chardata, actor);
        Debug1(LOG_NEWCHAR,me->clientnum,"Player Creation Complete");

        // Remove cached objects to make sure that the client gets a fresh character
        // list from the database if it logs out and in within 2 minutes.
        iCachedObject* obj = psserver->GetCacheManager()->RemoveFromCache(psserver->GetCacheManager()->MakeCacheName("list",client->GetAccountID().Unbox()));
        if(obj)
        {
            obj->ProcessCacheTimeout();
            obj->DeleteSelf();
        }
        obj = psserver->GetCacheManager()->RemoveFromCache(psserver->GetCacheManager()->MakeCacheName("auth",client->GetAccountID().Unbox()));
        if(obj)
        {
            obj->ProcessCacheTimeout();
            obj->DeleteSelf();
        }

        // Here everything is ok
        client->SetPID(chardata->GetPID());
        client->SetName(playerName);

        psCharApprovedMessage app(me->clientnum);
        if(app.valid)
            psserver->GetEventManager()->SendMessage(app.msg);
        else
            Bug2("Could not create valid psCharApprovedMessage for client %u.\n",me->clientnum);
    }
    else
    {
        psCharVerificationMesg mesg(me->clientnum);
        size_t z;
        //unfortunately count goes out of valid area so we need to check on charisma

        for(z = 0; z < psserver->GetCacheManager()->GetSkillAmount(); z++)
        {
            unsigned int rank = chardata->Skills().GetSkillRank((PSSKILL) z).Base();

            psSkillInfo* info = psserver->GetCacheManager()->GetSkillByID(z);
            csString name("Not found");
            if(info)
                name.Replace(info->name);

            if(rank > 0)
            {
                if(z >= PSSKILL_AGI && z <= PSSKILL_WILL)
                {
                    mesg.AddStat(rank, name);
                }
                else
                {
                    mesg.AddSkill(rank, name);
                }
            }
        }
        mesg.Construct();
        mesg.SendMessage();
    }

    delete actor;

    if(!upload.verify)
    {
        // Remove char data from the cache
        iCachedObject* obj = psserver->GetCacheManager()->RemoveFromCache(psserver->GetCacheManager()->MakeCacheName("char", chardata->GetPID().Unbox()));
        if(obj)
        {
            obj->ProcessCacheTimeout();
            obj->DeleteSelf();
        }
    }
}
Пример #16
0
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;
}
Пример #17
0
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);
}
Пример #18
0
int main(void)
{   
    uint32_t i, err;
    
    DelayInit();
    GPIO_QuickInit(HW_GPIOC, 10, kGPIO_Mode_OPP);
    
    #ifdef MK22F25612
    UART_QuickInit(UART0_RX_PB16_TX_PB17, 115200);
    #elif  MK20D5
    UART_QuickInit(UART1_RX_PC03_TX_PC04, 115200);
    #endif
    
    printf("program for Manley\r\n");

    swd_io_init();

    SWJ_InitDebug();
    
    SWJ_SetTargetState(RESET_HOLD);
    
    ShowID();
    for(i=0;i<sizeof(buf);i++)
    {
        buf[i] = i & 0xFF;
    }
    
    SWJ_WriteMem(0x20000000, buf, sizeof(buf));
    memset(buf, 0, sizeof(buf));
    SWJ_ReadMem(0x20000000, buf, sizeof(buf));

    for(i=0;i<sizeof(buf);i++)
    {
        if(buf[i] != (i & 0xFF))
        {
            printf("error buf[%d]:%d should be:%d\r\n", i, buf[i], i);
        }
    }
    
    printf("mem teset complete\r\n");
    
    
    SWJ_SetTargetState(RESET_PROGRAM);
    
    err =  TFlash_UnlockSequence();
    printf("TFlash_UnlockSequence %d\r\n", err);
    
    
    
    SWJ_SetTargetState(RESET_PROGRAM);
    
    err = TFlash_Init(&flash);
    printf("TFlash_Init %d\r\n", err);

    err = target_flash_program_page(&flash, 0x00000200, (uint8_t*)flash.image, 512);
    printf("target_flash_program_page %d\r\n", err);
    
    while(1)
    {
        GPIO_ToggleBit(HW_GPIOC, 10);
        DelayMs(500);
    }
}
Пример #19
0
void Tribe::Unbuild(NPC* npc, gemNPCItem* building)
{
    NPCDebug(npc, 6, "Unbuilding building %s",building->GetName());

    Asset* buildingAsset = GetAsset(building);
    if(buildingAsset)
    {
        buildingAsset->status = ASSET_STATUS_NOT_USED;
        buildingAsset->quantity = 0;
        SaveAsset(buildingAsset);

        // Check if there is a building spot that need to be downgrades as well
        csVector3 buildingPos = npc->GetTribe()->GetHomePosition();

        buildingPos -= buildingAsset->pos;

        Asset* buildingSpot = GetNearestAsset(Tribe::ASSET_TYPE_BUILDINGSPOT, buildingAsset->name, Tribe::ASSET_STATUS_CONSTRUCTED,
                                              buildingPos, NULL, 5.0, NULL);
        if(buildingSpot)
        {
            buildingSpot->status = Tribe::ASSET_STATUS_NOT_USED;
            SaveAsset(buildingSpot);

            // Now the building asset and the spot is freed inform the server
            npcclient->GetNetworkMgr()->QueueUnbuildCommand(npc->GetActor(), building);
        }
        else
        {
            Error4("NPC %s(%s) Failed to find building spot for building %s",npc->GetName(),ShowID(npc->GetEID()),building->GetName());
        }
    }
    else
    {
        Error4("NPC %s(%s) Failed to find building asset for building %s",npc->GetName(),ShowID(npc->GetEID()),building->GetName());
    }
}
Пример #20
0
bool GMEventManager::RemovePlayerFromGMEvents(PID playerID)
{
    int runningEventIDAsGM;
    int runningEventID, gmEventID;
    csArray<int> completedEventIDsAsGM;
    csArray<int> completedEventIDs;
    GMEvent* gmEvent;
    bool eventsFound = false;

    runningEventID = GetAllGMEventsForPlayer(playerID,
                                             completedEventIDs,
                                             runningEventIDAsGM,
                                             completedEventIDsAsGM);

    // remove if partaking in an ongoing event
    if (runningEventID >= 0)
    {
        gmEvent = GetGMEventByID(runningEventID);
        if (gmEvent)
        {
            size_t PlayerIndex = GetPlayerFromEvent(playerID, gmEvent);
            if(PlayerIndex != SIZET_NOT_FOUND)
            {
                gmEvent->Player.DeleteIndex(PlayerIndex);
                eventsFound = true;
            }
        }
        else
            Error3("Cannot remove player %s from GM Event %d.", ShowID(playerID), runningEventID);
    }
    // remove ref's to old completed events
    csArray<int>::Iterator evIter = completedEventIDs.GetIterator();
    while(evIter.HasNext())
    {
        gmEventID = evIter.Next();
        gmEvent = GetGMEventByID(gmEventID);
        if (gmEvent)
        {
            size_t PlayerIndex = GetPlayerFromEvent(playerID, gmEvent);
            if(PlayerIndex != SIZET_NOT_FOUND)
            {
                gmEvent->Player.DeleteIndex(PlayerIndex);
                eventsFound = true;
            }
         }
         else
            Error3("Cannot remove player %s from GM Event %d.", ShowID(playerID), runningEventID);
    }
    // ...and from the DB too
    if (eventsFound)
        db->Command("DELETE FROM character_events WHERE player_id = %u", playerID.Unbox());

    // if this is a GM thats being deleted, set its GMID to UNDEFINED_GMID.
    if (runningEventIDAsGM >= 0)
    {
        gmEvent = GetGMEventByID(runningEventIDAsGM);
        if (gmEvent)
        {
            gmEvent->gmID = UNDEFINED_GMID;
            db->Command("UPDATE gm_events SET gm_id = %d WHERE id = %d", UNDEFINED_GMID, gmEvent->id);
        }
        else
            Error3("Cannot remove GM %s from Event %d.", ShowID(playerID), runningEventID);
    }
    evIter = completedEventIDsAsGM.GetIterator();
    while(evIter.HasNext())
    {
        gmEventID = evIter.Next();
        gmEvent = GetGMEventByID(gmEventID);
        if (gmEvent)
        {
            gmEvent->gmID = UNDEFINED_GMID;
            db->Command("UPDATE gm_events SET gm_id = %d WHERE id = %d", UNDEFINED_GMID, gmEvent->id);
        }
        else
            Error3("Cannot remove GM %s from Event %d.", ShowID(playerID), gmEventID);
    }

    return true;
}
Пример #21
0
void Tribe::Advance(csTicks when, EventManager* eventmgr)
{
    int delta = when - lastAdvance;
    if(delta < 0)  // Handle wrappover of tick
    {
        delta = 250; // We just set it to the event timer.
    }
    lastAdvance = when;

    // Manage Wealth
    if(when - lastGrowth > 1000)
    {
        float growth;

        // We need to help tribes that have no members with some resources
        // so that they can spawn the first entity
        if(AliveCount() <= 0 && CountResource(wealthResourceName) < reproductionCost)
        {
            growth = wealthResourceGrowth;
        }
        else if(CountResource(wealthResourceName) < wealthResourceGrowthActiveLimit)
        {
            // Some tribes need constant growth in wealth, though capped to a limit
            // to prevent tribes with no strain on the resources to grow
            // infinit in wealth
            growth = wealthResourceGrowthActive;
        }
        else
        {
            growth = 0;
        }

        // Now calculate the growth. Adding what part that wasn't added
        // the last time this code where run.
        accWealthGrowth += growth* ((when - lastGrowth)/1000.0);
        int amount = int(floor(accWealthGrowth));
        accWealthGrowth -= amount;

        if(amount != 0) AddResource(wealthResourceName, amount);

        lastGrowth = when;
    }
    else if(when - lastGrowth < 0)  // Handle wrappoer of tick
    {
        lastGrowth = when;
    }

    // And manage tribe assignments
    csString perc;
    int      decreaseValue = delta; // Set it to change the scale on recipe wait times

    // Manage cyclic recipes
    for(size_t i=0; i<cyclicRecipes.GetSize(); i++)
    {
        cyclicRecipes[i].timeLeft -= decreaseValue;

        if(cyclicRecipes[i].timeLeft <= 0)
        {
            // Add the recipe and reset counter
            RecipeTreeNode* newNode = new RecipeTreeNode(cyclicRecipes[i].recipe, 0);
            tribalRecipe->AddChild(newNode);
            newNode->priority = CYCLIC_RECIPE_PRIORITY;
            cyclicRecipes[i].timeLeft = cyclicRecipes[i].timeTotal;
        }
    }

    // Manage standard recipes
    for(size_t i=0; i < members.GetSize(); i++)
    {
        NPC*       npc = members[i];
        Behavior*  behavior = npc->GetCurrentBehavior();

        // For dead npcs just resurrect them
        if(!npc->IsAlive())
        {
            // Issue the resurrect perception if we have enough
            // resources
            perc = "tribe:resurrect";
            Perception pcpt(perc);
            if(AliveCount() == 0 && (CountResource(wealthResourceName) >= 10 * reproductionCost))
            {
                AddResource(wealthResourceName, -10*reproductionCost);
                npc->TriggerEvent(&pcpt);
            }
            else if(CanGrow())
            {
                AddResource(wealthResourceName,-reproductionCost);
                npc->TriggerEvent(&pcpt);
            }
            continue;
        }

        // If we have any npcs with no assignments then
        // we can parse recipes and send them to work
        if(behavior && strcasecmp(behavior->GetName(),npcIdleBehavior.GetDataSafe())==0)
        {
            RDebug(this, 5, "*** Found Idle NPC %s(%s) checking recipes ***", npc->GetName(),ShowID(npc->GetEID()));

            // Update recipes wait times
            UpdateRecipeData(decreaseValue);

            // Get best recipe. (highest level, no wait time)
            RecipeTreeNode* bestRecipe = tribalRecipe->GetNextRecipe();

            if(!bestRecipe)
            {
                // Something went wrong... it should never re-parse the tribal recipe
                // High chances to be a scripting error
                break;
            }

            if(bestRecipe->wait <= 0)
            {
                RDebug(this, 5, "Applying recipe %s.", bestRecipe->recipe->GetName().GetDataSafe());

                bestRecipe->nextStep = recipeManager->ApplyRecipe(
                                           bestRecipe, this, bestRecipe->nextStep);
            }

            // If nextStep is -1 => Recipe is Completed
            if(bestRecipe->nextStep == -1)
            {
                // TODO -- Remove TimeStamp
                csString rName = bestRecipe->recipe->GetName();
                if(rName != "do nothing")
                {
                    RDebug(this, 5, "Recipe %s completed.", rName.GetData());
                }

                tribalRecipe->RemoveChild(bestRecipe->recipe);
            }

            // If nextStep is -2, the recipe has unmet requirements
            else if(bestRecipe->nextStep == -2)
            {
                bestRecipe->nextStep = 0;
            }
        }
    }
}