void NextEvent(MWEvent *event, int socket) { fd_set fdmask; XEvent xev; static int nexttimeoutinitialized=0; static struct timeval nexttimeout; struct timeval timeout,oldtime,newtime; int ret; char c; if (!nexttimeoutinitialized) { nexttimeoutinitialized=1; nexttimeout.tv_sec=app_resources.time_interval/1000; nexttimeout.tv_usec=1000*(app_resources.time_interval%1000); } while (1) { icon_flash = (++icon_flash) % ICON_FLASH_PERIOD; if (!XPending(dpy)) /* this does an XFlush, too */ if (flashIcon && !icon_flash && !mapped) { /* invert the icon */ iconInverted = !iconInverted; repaintIcon(); } /* * Look for events. Try to arrange that X events have priority over * network traffic. See if there's an X event pending. If so, check * for a net event, too; if not, select on both the network and the X * connection. If that doesn't time out, but there's no X event * pending, try again, just selecting on the X connection. If that * times out, let the network event get processed. * * Can't just select on the two fds, because there may be X events * pending in the queue that have already been read. * * This may look baroque, but we've seen some instances where X server * latency seems to let the network events take priority over sever * events, leading to sluggish keyboard response and lots of local * death. * */ if (!XPending(dpy)) { FD_ZERO(&fdmask); FD_SET(displayFD, &fdmask); FD_SET(socket, &fdmask); for (ret=0;ret<=0;) { if ((nexttimeout.tv_sec<0)|| ((nexttimeout.tv_sec==0)&&(nexttimeout.tv_usec<=0))) { nexttimeout.tv_sec=app_resources.time_interval/1000; nexttimeout.tv_usec= 1000*(app_resources.time_interval%1000); if (app_resources.robotic==TRUE) { event->eventType=RandomEvent(); return; } } timeout.tv_sec=nexttimeout.tv_sec; timeout.tv_usec=nexttimeout.tv_usec; gettimeofday(&oldtime,0); ret=select(32,&fdmask,NULL,NULL,&timeout); gettimeofday(&newtime,0); nexttimeout.tv_sec-=newtime.tv_sec-oldtime.tv_sec; nexttimeout.tv_usec-=newtime.tv_usec-oldtime.tv_usec; if (nexttimeout.tv_usec<0) { nexttimeout.tv_sec--; nexttimeout.tv_usec+=1000000; } if (ret==-1) { if (errno!=EINTR) MWError("select error on events"); } else if (ret==0) { nexttimeout.tv_sec=app_resources.time_interval/1000; nexttimeout.tv_usec= 1000*(app_resources.time_interval%1000); if (app_resources.robotic==TRUE) event->eventType=RandomEvent(); else event->eventType=EVENT_TIMEOUT; return; } } } else { FD_ZERO(&fdmask); FD_SET(socket, &fdmask); timeout.tv_sec = 0; timeout.tv_usec = 0; while ((ret = select(32, &fdmask, NULL, NULL, &timeout)) == -1) if (errno != EINTR) MWError("select error on events"); } if (XPending(dpy)) { XNextEvent(dpy, &xev); switch (xev.type) { case KeyPress: event->eventType = 0; XLookupString((XKeyEvent *) &xev, &c, 1, NULL, NULL); switch(c) { case 'a': case '4': /* keypad */ event->eventType = EVENT_A; return; case 's': case '5': event->eventType = EVENT_S; return; case 'd': case '6': event->eventType = EVENT_D; return; case 'f': case ',': event->eventType = EVENT_F; return; case ' ': case '\033': /* ESC lead in of arrow */ event->eventType = EVENT_BAR; return; case 'q': case '\177': /* DEL */ case '\003': /* ^C */ event->eventType = EVENT_INT; return; } break; #define RightButton Button3 #define MiddleButton Button2 #define LeftButton Button1 case ButtonPress: event->eventType = 0; switch(((XButtonPressedEvent *) &xev)->button & 0xff) { case RightButton: event->eventType = EVENT_RIGHT_D; return; case MiddleButton: event->eventType = EVENT_MIDDLE_D; return; case LeftButton: event->eventType = EVENT_LEFT_D; return; } break; case ButtonRelease: event->eventType = 0; switch(((XButtonReleasedEvent *) &xev)->button&0xff) { case RightButton: event->eventType = EVENT_RIGHT_U; return; case LeftButton: event->eventType = EVENT_LEFT_U; return; } break; case Expose: repaintWindow(); break; case FocusIn: case MapNotify: mapped = TRUE; iconInverted = FALSE; flashIcon = FALSE; repaintIcon(); break; case FocusOut: case UnmapNotify: mapped = FALSE; break; } } if (FD_ISSET(socket, &fdmask)) { socklen_t fromLen = sizeof(event->eventSource); int cc; event->eventType = EVENT_NETWORK; cc = recvfrom(socket, (char*)event->eventDetail, sizeof(MW244BPacket), 0, (struct sockaddr *)&event->eventSource, &fromLen); if (cc <= 0) { if (cc < 0 && errno != EINTR) perror("event recvfrom"); continue; } if (fromLen != sizeof(struct sockaddr_in)) continue; ConvertIncoming(event->eventDetail); return; } } }
void SteamScene::Update() { _timer += CherEngine::GTime.deltaTime; auto countLaunched = 0; for (int32_t i = 0; i < _spritesLaunched.size(); i++) { if (_spritesLaunched[i].launched) { countLaunched += 1; } } if (_timer > kDuration && countLaunched == 0) { _game.PlaySound("logoff"); _game.StartScene("wonScene"); return; } if (_timer >= kDuration - kOvedriveDuration && !_overdrive) { _overdrive = true; Overdrive(); } else if (_timer + _eventDuration < kDuration - kOvedriveDuration) { _nextEventTimer -= CherEngine::GTime.deltaTime; if (_nextEventTimer <= 0.0f) { _nextEventTimer += _game.RandomNumber(kMinNextEvent, kMaxNextEvent); RandomEvent(); } } if (_gabenEventOn || _steamsaleEventOn) { _eventTimer += CherEngine::GTime.deltaTime; if (_eventTimer > kEventAppearSpeed) { if (_steamsaleEventOn) { _bonusSpawn = kSteamSaleBonusSpawn; } if (_gabenEventOn) { _speedMultiplier = kGabenSpeedMultiplier; } } if (_eventTimer < _eventDuration - kEventBlinking) { if (_steamsaleEventOn) { _steamsale->SetAlpha(std::min(1.0f, _eventTimer / kEventAppearSpeed)); } if (_gabenEventOn) { _gaben->SetAlpha(std::min(1.0f, _eventTimer / kEventAppearSpeed)); } } else if (_eventTimer >= _eventDuration - kEventBlinking) { const auto alpha = (1.0f - std::fmod(_eventTimer - (_eventDuration - kEventBlinking), kEventBlinkingSpeed)) * 0.5f; if (_steamsaleEventOn) { _steamsale->SetAlpha(0.5f + alpha); } if (_gabenEventOn) { _gaben->SetAlpha(0.5f + alpha); } } if (_eventTimer >= _eventDuration) { if (_steamsaleEventOn) { _bonusSpawn = kDefaultBonusSpawn; _steamsaleEventOn = false; _steamsale->SetVisible(false); } if (_gabenEventOn) { _speedMultiplier = kDefaultSpeedMultiplier; _gabenEventOn = false; _gaben->SetVisible(false); } _eventTimer = 0.0f; } } _cursorTimer -= CherEngine::GTime.deltaTime; if (_cursorTimer <= 0.0f) { for (int32_t i = kCursorShadows - 1; i > 0; i--) { int32_t x = _cursorShadows[i - 1]->CenterX, y = _cursorShadows[i - 1]->CenterY; _cursorShadows[i]->SetCenterPosition(x, y); } int32_t x = CherEngine::GInput.MouseX, y = CherEngine::GInput.MouseY; CherEngine::GCamera.TransformMouse(x, y); _cursorShadows[0]->SetCenterPosition(x + 16, y + 16); _cursorTimer = 0.005f; } for (int32_t i = 0; i < _spritesLaunched.size(); i++) { auto& icon = _gameIcons[i]; auto& spriteLaunched = _spritesLaunched[i]; if (spriteLaunched.launched && !spriteLaunched.split) { spriteLaunched.t += _speedMultiplier * CherEngine::GTime.deltaTime; auto x = spriteLaunched.initialX + spriteLaunched.direction * (spriteLaunched.velocity * spriteLaunched.t * std::cos(spriteLaunched.angle)); auto y = spriteLaunched.initialY - (spriteLaunched.velocity * spriteLaunched.t * std::sin(spriteLaunched.angle)) + (0.5f * g * spriteLaunched.t * spriteLaunched.t); icon->GetMasterSprite()->SetCenterPosition(static_cast<int32_t>(x), static_cast<int32_t>(y)); if (y > kBottomborder) { spriteLaunched.launched = false; icon->SetVisible(false); _fullSpace = std::min(_fullSpace + icon->Weight, kCapacity); const auto pc = _fullSpace / kCapacity; if (pc > 0.75f && !_spacebarRed->GetVisible()) { _spacebarRed->SetVisible(true); _spacebarBlue->SetVisible(false); } if (_fullSpace >= kCapacity) { _game.PlaySound("logoff"); _game.StartScene("lostScene"); return; } else { _game.PlaySound("hardwarefail"); } _spacebarBlue->SetWidthPercentage(pc); _spacebarRed->SetWidthPercentage(pc); } if (!spriteLaunched.split) { for (int32_t i = kCursorShadows - 1; i >= 0; i--) { // Find first shadow inside auto cursorShadow = _cursorShadows[i]; if (icon->GetMasterSprite()->IsInside(cursorShadow->CenterX - 16, cursorShadow->CenterY - 16)) { CherEngine::Sprite* firstLeftOutsideShadow = nullptr; CherEngine::Sprite* firstRightOutsideShadow = nullptr; for (int32_t j = i - 1; j >= 0; j--) { auto potentialShadow = _cursorShadows[j]; if (!icon->GetMasterSprite()->IsInside(potentialShadow->CenterX - 16, potentialShadow->CenterY - 16)) { firstLeftOutsideShadow = potentialShadow; break; } } for (int32_t j = i + 1; j < kCursorShadows; j++) { auto potentialShadow = _cursorShadows[j]; if (!icon->GetMasterSprite()->IsInside(potentialShadow->CenterX - 16, potentialShadow->CenterY - 16)) { firstRightOutsideShadow = potentialShadow; break; } } if (firstLeftOutsideShadow != nullptr && firstRightOutsideShadow != nullptr) { const int xDiff = std::abs(firstLeftOutsideShadow->CenterX - firstRightOutsideShadow->CenterX); const int yDiff = std::abs(firstLeftOutsideShadow->CenterY - firstRightOutsideShadow->CenterY); LD42::SplitDirection direction; if (xDiff == 0) { direction = kSplitDirection_Vertical; } else if (yDiff == 0) { direction = kSplitDirection_Horizontal; } else { const auto angle = std::atan2(yDiff, xDiff); const auto lX = firstLeftOutsideShadow->CenterX; const auto rX = firstRightOutsideShadow->CenterX; const auto lY = firstLeftOutsideShadow->CenterY; const auto rY = firstRightOutsideShadow->CenterY; if (angle < Deg2Rad * 23) { direction = kSplitDirection_Horizontal; } else if (angle < Deg2Rad * (45 + 23) && ((lX < rX && lY < rY) || (lX > rX && lY > rY))) { direction = kSplitDirection_DiagonalLR; } else if (angle < Deg2Rad * (45 + 23) && ((lX > rX && lY < rY) || (lX < rX && lY > rY))) { direction = kSplitDirection_DiagonalRL; } else { direction = kSplitDirection_Vertical; } } spriteLaunched.split = true; spriteLaunched.initialMasterX = icon->GetMasterSprite()->CenterX; spriteLaunched.initialMasterY = icon->GetMasterSprite()->CenterY; spriteLaunched.t = 0.0f; switch (direction) { case LD42::kSplitDirection_Horizontal: spriteLaunched.velocityX = 0; spriteLaunched.velocityY = 20; break; case LD42::kSplitDirection_Vertical: spriteLaunched.velocityX = -30; spriteLaunched.velocityY = 0; break; case LD42::kSplitDirection_DiagonalLR: spriteLaunched.velocityX = 15; spriteLaunched.velocityY = 10; break; case LD42::kSplitDirection_DiagonalRL: spriteLaunched.velocityX = -15; spriteLaunched.velocityY = 10; break; default: break; } _game.PlaySound("recycle"); icon->Split(direction); } break; } } } } else if (spriteLaunched.launched && spriteLaunched.split) { spriteLaunched.t += _speedMultiplier * CherEngine::GTime.deltaTime; auto x = spriteLaunched.initialMasterX + (spriteLaunched.velocityX * spriteLaunched.t); auto y = spriteLaunched.initialMasterY - (spriteLaunched.velocityY * spriteLaunched.t) + (0.5f * g * spriteLaunched.t * spriteLaunched.t); icon->GetMasterSprite()->SetCenterPosition(static_cast<int32_t>(x), static_cast<int32_t>(y)); auto xSecond = spriteLaunched.initialMasterX + (-spriteLaunched.velocityX * spriteLaunched.t); auto ySecond = spriteLaunched.initialMasterY - (-spriteLaunched.velocityY * spriteLaunched.t) + (0.5f * g * spriteLaunched.t * spriteLaunched.t); icon->GetSecondMasterSprite()->SetCenterPosition(static_cast<int32_t>(xSecond), static_cast<int32_t>(ySecond)); if (y > kBottomborder && ySecond > kBottomborder) { spriteLaunched.launched = false; spriteLaunched.split = false; icon->SetVisible(false); icon->Restore(); } } } _launchTimer -= CherEngine::GTime.deltaTime; if (_launchTimer <= 0.0f && _timer < kDuration) { auto launchCount = _bonusSpawn + _game.RandomPoisson(); for (size_t i = 0; i < launchCount; i++) { LaunchRandomnIcon(); } // Always launch at least one if (launchCount == 0) { LaunchRandomnIcon(); } _launchTimer = _launchDelay; } }