bool InvestigationScene::tick(double dt) {
    
    if (inputLocked) {
        return true;
    }
    
    int tx = playerSprite->getPosition().x / collision->getTileSize().width;
    int ty = playerSprite->getPosition().y / collision->getTileSize().height;
    
    std::vector<Room *> rooms = mystery->getRooms();
    std::vector<Room *>::iterator itRooms;
    for (itRooms = rooms.begin(); itRooms < rooms.end(); ++itRooms) {
        Room *room = (Room *) *itRooms;
        
        if (rectContainsPoint(room->bounds, pointMake(tx, ty)) && room != currentRoom) {
            currentRoom = room;
            currentRoomLabel->setText(room->name.c_str());
        }
    }
    
    float dx = 0;
    float dy = 0;
    
    bool isMoving = !pointEqualsIntegral(moving, pointMake(0, 0));
    
    if (isMoving) {
        
        dx = moving.x * 200 * dt;
        dy = moving.y * 200 * dt;
        
        if (dy < 0) {
            moveDir = 0;
        } else if (dy > 0) {
            moveDir = 18;
        } else if (dx < 0) {
            moveDir = 9;
        } else if (dx > 0) {
            moveDir = 27;
        }
        
        curFrame += dt * 10;
        if (curFrame > 8) curFrame -= 8;
        
    } else {
        
        curFrame = 0;
    }
    
    bool collided = false;
    
    Rect colRect = rectMake(playerSprite->getPosition().x - 16, playerSprite->getPosition().y - 16, 32, 32);
    
    Rect colRectX = rectOffset(colRect, dx, 0);
    Rect colRectY = rectOffset(colRect, 0, dy);
    
    int tw = collision->getTileSize().width;
    int th = collision->getTileSize().height;
    
    int tpx = playerSprite->getPosition().x / collision->getTileSize().width;
    int tpy = playerSprite->getPosition().y / collision->getTileSize().height;
    
    for (int j = tpy - 2; j <= tpy + 2; j++) {
        for (int i = tpx - 2; i <= tpx + 2; i++) {
            
            if (i >= 0 && i < collision->getSize().width && j >= 0 && j < collision->getSize().height) {
                int gid = collision->getTileAt(i, j);
                
                if (gid != 0) {
                    
                    Rect tileRect = rectMake(i * tw, j * th, tw, th);
                    
                    if (rectIntersectsRect(colRectX, tileRect)) {
                        dx = 0;
                        collided = true;
                    }
                    
                    if (rectIntersectsRect(colRectY, tileRect)) {
                        dy = 0;
                        collided = true;
                    }
                }
            }
        }
    }
    
    actionButton->setVisible(false);
    actionButton->setEnabled(false);
    
    activeCharacter = NULL;
    activePOI = NULL;
    
    std::vector<Character *> characters = mystery->getCharacters();
    std::vector<Character *>::iterator it;
    
    for (it = characters.begin(); it < characters.end(); ++it) {
        
        Character *character = (Character *) *it;
        
        std::string action;
        
        if (character->dead) {
            action.append("Look at ");
        } else {
            action.append("Talk to ");
        }
        
        action.append(character->name);
        
        Drawable *sprite = getByTag(character->tag);
        
        Rect otherColRect = rectMake(sprite->getPosition().x - 16, sprite->getPosition().y - 16, 32, 32);
        
        if (rectIntersectsRect(colRect, otherColRect)) {
            actionButton->setLabelText(action.c_str());
            actionButton->setPosition(pointMake(sprite->getPosition().x, sprite->getPosition().y - 32));
            actionButton->setVisible(true);
            actionButton->setEnabled(true);
            
            activeCharacter = character;
        }
    }
    
    if (currentRoom != NULL) {
        
        std::vector<POI *> POIList = currentRoom->pointsOfInterest;
        std::vector<POI *>::iterator itPOI;
        
        for (itPOI = POIList.begin(); itPOI < POIList.end(); ++itPOI) {
            
            POI *poi = (POI *) *itPOI;
            
            Rect tileRect = collision->getTileRect(poi->position.x, poi->position.y);
            tileRect = rectExpand(tileRect, 4, 4);
            
            if ((poi->interest == InterestContainerVisible || poi->interest == InterestContainerConceiled) && rectIntersectsRect(colRect, tileRect)) {
                
                std::string action = "Examine ";
                action.append(poi->shortDescription);
                
                actionButton->setLabelText(action.c_str());
                actionButton->setPosition(rectMidPoint(tileRect));
                actionButton->setVisible(true);
                actionButton->setEnabled(true);
                
                activePOI = poi;
            }
        }
    }
    
    playerSprite->setFrame(moveDir + (int)curFrame + (isMoving ? 1 : 0));
    playerSprite->setPosition(pointOffset(playerSprite->getPosition(), dx, dy));
    
    camera->setCenter(playerSprite->getPosition());
    
    return !endScene;
}
Пример #2
0
static inline bool rectContainsRect(const CvRect& parent, const CvRect &child)        // contains or equals, but not associative
{
    return rectContainsPoint(parent, child.x, child.y) && 
        rectContainsPoint(parent, child.x + child.width - 1, child.y + child.height - 1);
}
Пример #3
0
void Mystery::step() {

    if (ended) {
        return;
    }

    AStarSearch<MapSearchNode> astarsearch;

    std::vector<Character *>::iterator itChars;
    for (itChars = characters.begin(); itChars < characters.end(); ++itChars) {

        Character *character = (Character *) *itChars;

        if (character->dead) {
            continue;
        }

        if (character->idle) {

            int targetX = 0;
            int targetY = 0;

            // Any dead people in the same room?

            Character *corpseInRoom = NULL;

            std::vector<Character *>::iterator itOthers;
            for (itOthers = characters.begin(); itOthers < characters.end(); ++itOthers) {
                Character *other = (Character *) *itOthers;
                if (other->currentRoom == character->currentRoom && other->dead) {
                    corpseInRoom = other;
                }
            }

            // Does the character want to chat?
            bool wantsToTalk = rand() % 2 == 0;

            if (corpseFound && (character->murderTarget == NULL || (character->murderTarget != NULL && character->carryingWeapon == NULL))) {

                targetX = victim->position.x;
                targetY = victim->position.y;

                character->currentTarget = NULL;

            } else if (corpseInRoom != NULL && character->murderTarget == NULL) {

                // Go look at the corpse

                targetX = corpseInRoom->position.x;
                targetY = corpseInRoom->position.y;

                character->currentTarget = NULL;

            } else if (character->murderTarget != NULL && !character->murderTarget->dead && character->carryingWeapon != NULL && character->timeBeforeTryMurder == 0) {

                // Murderer goes after its target if he has a weapon and the target is
                // not dead yet

                targetX = character->murderTarget->position.x;
                targetY = character->murderTarget->position.y;

                character->currentTarget = NULL;

            } else if (wantsToTalk) {

                // Goes after another character

                int idxOption = rand() % characters.size();
                Character *option = characters[idxOption];
                targetX = option->position.x;
                targetY = option->position.y;

                character->currentTarget = NULL;

            } else {

                // Looks for a POI matching the characters interest in any room

                Room *room;
                std::vector<POI *> points;

                bool notSearchedOnly = false;

                Interest interest = character->interest;
                if (character->murderTarget != NULL && ((character->carryingWeapon == NULL && character->timeBeforeSearchWeapon == 0 && !character->murderTarget->dead) || (character->carryingWeapon != NULL && character->murderTarget->dead))) {

                    // If the character is a murderer and is looking for a weapon, or
                    // if he/she already killed the target, he/she goes to a container
                    // to grab/hide the weapon

                    if (character->carryingWeapon != NULL) {
                        interest = InterestContainerConceiled;
                    } else {
                        interest = InterestContainerVisible;
                    }

                    // If he has no weapon, searches only the containers not
                    // searched yet

                    notSearchedOnly = character->carryingWeapon == NULL;

                } else {

                    // There's a chance the character wants to see a container
                    int chance = rand() % 100;

                    if (chance < 25) {
                        interest = InterestContainerVisible;
                    } else if (chance < 50) {
                        interest = InterestContainerConceiled;
                    }
                }

                do {
                    int roomIdx = rand() % rooms.size();
                    room = rooms[roomIdx];

                    points = room->getPointsOfInterest(interest, notSearchedOnly);

                } while (points.size() == 0);

                // Goes after an interesting random POI

                int idx = rand() % points.size();
                POI *poi = points[idx];

                character->currentTarget = poi;

                targetX = poi->position.x;
                targetY = poi->position.y;
            }

            character->idle = false;

            MapSearchNode nodeStart;
            nodeStart.x = (int) character->position.x;
            nodeStart.y = (int) character->position.y;
            nodeStart.mystery = this;

            MapSearchNode nodeEnd;
            nodeEnd.x = targetX;
            nodeEnd.y = targetY;
            nodeEnd.mystery = this;

            astarsearch.SetStartAndGoalStates(nodeStart, nodeEnd);

            unsigned int SearchState;

            do {

                SearchState = astarsearch.SearchStep();

            } while( SearchState == AStarSearch<MapSearchNode>::SEARCH_STATE_SEARCHING );

            // Found a path to the target

            if (SearchState == AStarSearch<MapSearchNode>::SEARCH_STATE_SUCCEEDED) {

                MapSearchNode *node = astarsearch.GetSolutionStart();

                while (node) {

                    // Builds the steps for the character to reach its target

                    Step *step = new Step();
                    step->position = pointMake(node->x, node->y);
                    step->conversationWith = NULL;
                    step->type = StepTypeWalk;
                    step->duration = STEP_DURATION;

                    if (character->currentTarget != NULL && pointEqualsIntegral(step->position, character->currentTarget->position)) {

                        Step *step = new Step();
                        step->position = pointMake(node->x, node->y);
                        step->conversationWith = NULL;
                        step->type = StepTypeStartInteractPOI;
                        step->duration = 1;

                        character->addStep(step);

                        step = new Step();
                        step->position = pointMake(node->x, node->y);
                        step->conversationWith = NULL;
                        step->type = StepTypeInteractPOI;
                        step->duration = rand() % MAX_DURATION_POI_INTERACTION + MIN_DURATION_POI_INTERACTION;

                        character->addStep(step);

                        step = new Step();
                        step->position = pointMake(node->x, node->y);
                        step->conversationWith = NULL;
                        step->type = StepTypeEndInteractPOI;
                        step->duration = 1;

                        character->addStep(step);

                    } else {

                        Step *step = new Step();
                        step->position = pointMake(node->x, node->y);
                        step->conversationWith = NULL;
                        step->type = StepTypeWalk;
                        step->duration = STEP_DURATION;

                        character->addStep(step);
                    }

                    node = astarsearch.GetSolutionNext();
                }

                astarsearch.FreeSolutionNodes();
            }

        } else {

            // Updates the character's path by 1 unit of time

            character->updatePath();

            if (!character->isHavingConversation() && character->conversationInterval > 0) {
                character->conversationInterval--;
            }

            if (character->timeBeforeSearchWeapon > 0) {
                character->timeBeforeSearchWeapon--;
            } else {

                if (character->timeBeforeTryMurder > 0 && character->carryingWeapon != NULL) {
                    character->timeBeforeTryMurder--;
                }
            }

            Room *currentRoom = NULL;

            // Determines if the character entered or left a room

            std::vector<Room *>::iterator itRooms;
            for (itRooms = rooms.begin(); itRooms < rooms.end(); ++itRooms) {
                Room *room = (Room *) *itRooms;

                if (rectContainsPoint(room->bounds, character->position)) {
                    currentRoom = room;
                }
            }

            if (currentRoom != character->currentRoom) {

                if (character->currentRoom != NULL) {
                    printf("%s left %s\n", character->name.c_str(), character->currentRoom->name.c_str());
                    registerEventForAllInRoom(EventLeftRoom, character, NULL, character->currentRoom, NULL, NULL);
                }

                character->currentRoom = currentRoom;

                if (character->currentRoom != NULL) {
                    printf("%s entered %s\n", character->name.c_str(), character->currentRoom->name.c_str());
                    registerEventForAllInRoom(EventEnteredRoom, character, NULL, character->currentRoom, NULL, NULL);

                    if (character != murderer) {
                        // Register any weapons saw before but missing
                        std::vector<Memory *>::iterator it;
                        std::vector<Memory *> memories = character->getMemories();
                        std::vector<Memory *> considered;

                        for (it = memories.begin(); it < memories.end(); ++it) {

                            Memory *memory = (Memory *) *it;

                            if (memory->event == EventSawWeapon && memory->where == character->currentRoom && memory->when < time && !pointEqualsIntegral(memory->whatInside->position, memory->what->visualPosition)) {

                                std::vector<Memory *>::iterator itOther;

                                bool found = false;

                                for (itOther = considered.begin(); itOther < considered.end(); ++itOther) {

                                    Memory *other = (Memory *) *itOther;

                                    if (other->where == memory->where && other->whatInside == memory->whatInside) {
                                        found = true;
                                        break;
                                    }
                                }

                                if (!found) {
                                    registerEventFor(character, EventWeaponMissing, NULL, NULL, character->currentRoom, memory->what, memory->whatInside);
                                    considered.push_back(memory);
                                }
                            }
                        }
                    }

                    // Register visible weapons the character sees in the room
                    std::vector<POI *>::iterator itPOI;
                    for (itPOI = character->currentRoom->pointsOfInterest.begin(); itPOI < character->currentRoom->pointsOfInterest.end(); ++itPOI) {

                        POI *poi = (POI *) *itPOI;

                        if (poi->interest == InterestContainerVisible && poi->contents != NULL && poi->contents->isWeapon()) {
                            registerEventFor(character, EventSawWeapon, NULL, NULL, character->currentRoom, poi, poi->contents);
                        }
                    }

                    std::vector<Character *>::iterator itOthers;
                    for (itOthers = characters.begin(); itOthers < characters.end(); ++itOthers) {
                        Character *other = (Character *) *itOthers;

                        if (other != character && other->currentRoom == character->currentRoom) {

                            registerEventFor(character, EventWasInRoom, other, NULL, character->currentRoom, NULL, NULL);

                            // Register others having conversations
                            if (other->isHavingConversation()) {
                                Character *another = other->getCurrentStep()->conversationWith;
                                registerEventFor(character, EventWasHavingConversation, other, another, character->currentRoom, NULL, NULL);
                            }

                            // Register others interacting with POIs
                            if (other->isInteractingWithPOI()) {
                                registerEventFor(character, EventWasInteractingPOI, other, NULL, character->currentRoom, other->currentTarget, NULL);
                            }
                        }
                    }
                }
            }

            if (character->getCurrentStep() != NULL) {

                Character *another;

                switch (character->getCurrentStep()->type) {
                case StepTypeStartInteractPOI:
                    registerEventForAllInRoom(EventStartInteractPOI, character, NULL, character->currentRoom, character->currentTarget, NULL);
                    break;
                case StepTypeEndInteractPOI:
                    another = character->getCurrentStep()->conversationWith;
                    registerEventForAllInRoom(EventEndInteractPOI, character, another, character->currentRoom, character->currentTarget, NULL);
                    break;
                case StepTypeEndConversation:
                    another = character->getCurrentStep()->conversationWith;
                    registerEventForAllInRoom(EventEndConversation, character, another, character->currentRoom, NULL, NULL);
                    break;
                default:
                    break;
                }
            }

            bool aloneInRoom = true;
            bool aloneInRoomWithVictim = true;
            bool allNearCorpse = pointEqualsIntegral(character->position, victim->position);

            std::vector<Character *>::iterator itOthers;
            for (itOthers = characters.begin(); itOthers < characters.end(); ++itOthers) {
                Character *other = (Character *) *itOthers;

                allNearCorpse = allNearCorpse && pointEqualsIntegral(other->position, victim->position);

                if (other != character) {
                    if (character->currentRoom == other->currentRoom) {
                        aloneInRoom = false;

                        if (other != character->murderTarget) {
                            aloneInRoomWithVictim = false;
                        }
                    }

                    if (victim->dead && other == victim && pointEqualsIntegral(character->position, other->position) && !corpseFound) {

                        printf("*** %s found %s's body in the %s ***\n", character->name.c_str(), victim->name.c_str(), character->currentRoom->name.c_str());
                        corpseFound = true;
                        corpseFoundTime = time;
                        corpseFoundRoom = character->currentRoom;
                        character->clearPath();

                        std::vector<Character *>::iterator itAll;
                        for (itAll = characters.begin(); itAll < characters.end(); ++itAll) {
                            registerEventFor(*itAll, EventFoundBody, character, NULL, corpseFoundRoom, NULL, NULL);
                        }
                    }

                    // Looks for:
                    // - adjacent characters
                    // - one of them without a POI in mind
                    // - both not already in a conversation
                    // - both conversation intervals expired

                    if (pointAdjacentIntegral(character->position, other->position) &&
                            (character->currentTarget == NULL || other->currentTarget == NULL) &&
                            (!character->isHavingConversation() && !other->isHavingConversation()) &&
                            (character->conversationInterval == 0 && other->conversationInterval == 0) && !corpseFound) {

                        int duration = rand() % MAX_DURATION_CONVERSATION + MIN_DURATION_CONVERSATION;

                        // If both characters have matching interests, the talk is longer

                        if (character->interest == other->interest) {
                            duration *= CONVERSATION_INTEREST_FACTOR;
                        }

                        character->clearPath();
                        other->clearPath();

                        Step *step = new Step();
                        step->position = character->position;
                        step->duration = duration;
                        step->conversationWith = other;
                        step->type = StepTypeConversation;
                        character->addStep(step);

                        step = new Step();
                        step->position = character->position;
                        step->duration = 1;
                        step->conversationWith = other;
                        step->type = StepTypeEndConversation;
                        character->addStep(step);

                        step = new Step();
                        step->position = other->position;
                        step->duration = duration;
                        step->conversationWith = character;
                        step->type = StepTypeConversation;
                        other->addStep(step);

                        step = new Step();
                        step->position = other->position;
                        step->duration = 1;
                        step->conversationWith = character;
                        step->type = StepTypeEndConversation;
                        other->addStep(step);

                        character->conversationInterval = CONVERSATION_INTERVAL;
                        other->conversationInterval = CONVERSATION_INTERVAL;

                        registerEventForAllInRoom(EventStartConversation, character, other, character->currentRoom, NULL, NULL);
                        registerEventForAllInRoom(EventStartConversation, other, character, character->currentRoom, NULL, NULL);

                        printf("%s and %s are having a conversation\n", character->name.c_str(), other->name.c_str());

                    }
                }
            }

            if (allNearCorpse && corpseFound) {
                ended = true;
                printf("*** Mystery finished ***\n");
            }

            // Murderer-specific actions

            if (character->murderTarget != NULL) {

                // Grabs a weapon if:
                // - interval elapsed
                // - not carrying a weapon already
                // - murder target is not dead
                // - has a target POI
                // - reached the target POI
                // - POI has contents
                // - POI's content is a weapon matching interest
                // - alone in the room

                if (character->timeBeforeSearchWeapon == 0 &&
                        character->carryingWeapon == NULL &&
                        !victim->dead &&
                        character->currentTarget != NULL &&
                        pointEqualsIntegral(character->position, character->currentTarget->position) &&
                        character->currentTarget->contents != NULL &&
                        character->currentTarget->contents->interest == character->weaponInterest &&
                        aloneInRoom) {

                    character->carryingWeapon = character->currentTarget->contents;
                    character->carryingWeapon->position = pointMake(-20, -20);
                    character->currentTarget->contents = NULL;

                    printf("*** %s got a %s! ***\n", character->name.c_str(), character->carryingWeapon->description.c_str());
                }

                // Kills the victim if:
                // - interval elapsed
                // - already got a weapon
                // - near the victim
                // - murder target is not dead
                // - alone in the room with victim

                if (character->timeBeforeTryMurder == 0 &&
                        character->carryingWeapon != NULL &&
                        pointAdjacentIntegral(character->position, victim->position) &&
                        !victim->dead &&
                        aloneInRoomWithVictim) {

                    printf("*** %s murdered %s! ***\n", character->name.c_str(), victim->name.c_str());
                    victim->dead = true;
                    crimeWeapon = character->carryingWeapon;

                    character->clearPath();

                    // Murderer will lie

                    int idx = rand() % character->currentRoom->pointsOfInterest.size();
                    POI *poi = character->currentRoom->pointsOfInterest[idx];

                    registerEventFor(character, EventStartInteractPOI, character, NULL, character->currentRoom, poi, NULL);
                    registerEventFor(character, EventEndInteractPOI, character, NULL, character->currentRoom, poi, NULL);
                }

                // Hides the weapon if:
                // - carrying a weapon
                // - murder target is dead
                // - has a target POI
                // - reached the target POI
                // - POI has no contents
                // - alone in the room

                if (character->carryingWeapon != NULL &&
                        victim->dead &&
                        character->currentTarget != NULL &&
                        pointEqualsIntegral(character->position, character->currentTarget->position) &&
                        character->currentTarget->contents == NULL &&
                        aloneInRoom) {

                    character->carryingWeapon->position = character->currentTarget->visualPosition;

                    if (character->currentTarget->interest == InterestContainerConceiled) {
                        character->carryingWeapon->position = pointMake(-20, -20);
                    }

                    character->currentTarget->contents = character->carryingWeapon;
                    character->carryingWeapon = NULL;

                    printf("*** %s hid the %s in the %s, in the %s! ***\n", character->name.c_str(), character->currentTarget->contents->description.c_str(), character->currentTarget->description.c_str(), currentRoom->name.c_str());
                }
            }
        }
    }

    astarsearch.EnsureMemoryFreed();

    time++;
}