/** * @brief Called every frame and checks whether a timed particle should be spawned */ static void CL_ParticleRunTimed (void) { int i; const size_t length = lengthof(timedParticles); for (i = 0; i < length; i++) { timedParticle_t *tp = &timedParticles[i]; if (!tp->parent || !tp->parent->inuse) continue; if (tp->n >= tp->max) continue; if (CL_Milliseconds() - tp->lastTime < tp->dt) continue; { ptl_t *p; if (!tp->n) { /* first spawn? - then copy the parent values. We have to * do this here and now earlier because projectile particles * get these values set after spawn. */ VectorCopy(tp->parent->s, tp->s); VectorCopy(tp->parent->v, tp->v); VectorCopy(tp->parent->a, tp->a); } tp->n++; tp->lastTime = CL_Milliseconds(); p = CL_ParticleSpawn(tp->ptl, tp->levelFlags, tp->s, tp->v, tp->a); if (p && tp->children) { p->next = tp->parent->children; p->parent = tp->parent; tp->parent->children = p; } } } }
static void CL_Reconnect (void) { if (cls.reconnectTime == 0 || cls.reconnectTime > CL_Milliseconds()) return; Com_Printf("Reconnecting...\n"); CL_Disconnect(); CL_SetClientState(ca_connecting); /* otherwise we would time out */ cls.connectTime = CL_Milliseconds() - 1500; }
void uiTextEntryNode::draw (uiNode_t* node) { const float* textColor; vec2_t pos; const char* font = UI_GetFontFromNode(node); uiSpriteStatus_t iconStatus = SPRITE_STATUS_NORMAL; if (node->disabled) { textColor = node->disabledColor; iconStatus = SPRITE_STATUS_DISABLED; } else if (node->state) { textColor = node->color; iconStatus = SPRITE_STATUS_HOVER; } else { textColor = node->color; } if (UI_HasFocus(node)) { textColor = node->selectedColor; } UI_GetNodeAbsPos(node, pos); if (EXTRADATA(node).background) { UI_DrawSpriteInBox(false, EXTRADATA(node).background, iconStatus, pos[0], pos[1], node->box.size[0], node->box.size[1]); } if (char const* const text = UI_GetReferenceString(node, node->text)) { char buf[MAX_VAR]; if (EXTRADATA(node).isPassword) { size_t size = UTF8_strlen(text); if (size > MAX_VAR - 2) size = MAX_VAR - 2; memset(buf, HIDECHAR, size); buf[size] = '\0'; } else { /* leave one byte empty for the text-based cursor */ UTF8_strncpyz(buf, text, sizeof(buf) - 1); } /** @todo Make the cursor into a real graphical object instead of using a text character. */ if (UI_HasFocus(node)) { if (CL_Milliseconds() % 1000 < 500) { UTF8_insert_char_at(buf, sizeof(buf), EXTRADATA(node).cursorPosition, (int)CURSOR_ON); } else { UTF8_insert_char_at(buf, sizeof(buf), EXTRADATA(node).cursorPosition, (int)CURSOR_OFF); } } if (*buf != '\0') { R_Color(textColor); UI_DrawStringInBox(font, (align_t)node->contentAlign, pos[0] + node->padding, pos[1] + node->padding, node->box.size[0] - node->padding - node->padding, node->box.size[1] - node->padding - node->padding, buf); R_Color(nullptr); } } }
/** * @brief * @note Called after precache was sent from the server * @sa SV_Configstrings_f * @sa CL_Precache_f */ void CL_RequestNextDownload (void) { if (cls.state != ca_connected) { Com_Printf("CL_RequestNextDownload: Not connected (%i)\n", cls.state); return; } /* Use the map data from the server */ cl.mapTiles = SV_GetMapTiles(); cl.mapData = SV_GetMapData(); /* as a multiplayer client we have to load the map here and * check the compatibility with the server */ if (!Com_ServerState() && !CL_CanMultiplayerStart()) return; CL_ViewLoadMedia(); dbuffer msg(7); /* send begin */ /* this will activate the render process (see client state ca_active) */ NET_WriteByte(&msg, clc_stringcmd); /* see CL_StartGame */ NET_WriteString(&msg, NET_STATE_BEGIN "\n"); NET_WriteMsg(cls.netStream, msg); cls.waitingForStart = CL_Milliseconds(); S_MumbleLink(); }
/** * @note Only call @c CL_Connect if there is no connection yet (@c cls.netStream is @c nullptr) * @sa CL_Disconnect * @sa CL_SendChangedUserinfos */ static void CL_Connect (void) { Com_SetUserinfoModified(false); assert(!cls.netStream); if (cls.servername[0] != '\0') { assert(cls.serverport[0] != '\0'); Com_Printf("Connecting to %s %s...\n", cls.servername, cls.serverport); cls.netStream = NET_Connect(cls.servername, cls.serverport, CL_FreeClientStream); } else { Com_Printf("Connecting to localhost...\n"); cls.netStream = NET_ConnectToLoopBack(CL_FreeClientStream); } if (cls.netStream) { char info[MAX_INFO_STRING]; NET_OOB_Printf(cls.netStream, SV_CMD_CONNECT " %i \"%s\"\n", PROTOCOL_VERSION, Cvar_Userinfo(info, sizeof(info))); cls.connectTime = CL_Milliseconds(); } else { if (cls.servername[0] != '\0') { assert(cls.serverport[0]); Com_Printf("Could not connect to %s %s\n", cls.servername, cls.serverport); } else { Com_Printf("Could not connect to localhost\n"); } } }
/** * @sa CL_SendCommand */ void IN_SendKeyEvents (void) { while (keyq_head != keyq_tail) { Key_Event(keyq[keyq_tail].key, keyq[keyq_tail].unicode, keyq[keyq_tail].down, CL_Milliseconds()); keyq_tail = (keyq_tail + 1) & (MAX_KEYQ - 1); } }
/** * @brief Restart a timer */ void UI_TimerStart (uiTimer_t *timer) { if (timer->isRunning) return; assert(ui_firstTimer != timer && timer->prev == nullptr && timer->next == nullptr); timer->nextTime = CL_Milliseconds() + timer->delay; timer->isRunning = true; UI_InsertTimerInActiveList(ui_firstTimer, timer); }
/** * @sa CL_Frame */ static void CL_SendCommand (void) { /* get new key events */ IN_SendKeyEvents(); /* process console commands */ Cbuf_Execute(); /* send intentions now */ CL_SendChangedUserinfos(); /* fix any cheating cvars */ Cvar_FixCheatVars(); switch (cls.state) { case ca_disconnected: /* if the local server is running and we aren't connected then connect */ if (Com_ServerState()) { cls.servername[0] = '\0'; cls.serverport[0] = '\0'; CL_SetClientState(ca_connecting); return; } break; case ca_connecting: if (CL_Milliseconds() - cls.connectTime > cl_connecttimeout->integer) { if (GAME_IsMultiplayer()) Com_Error(ERR_DROP, "Server is not reachable"); } break; case ca_connected: if (cls.waitingForStart) { if (CL_Milliseconds() - cls.waitingForStart > cl_connecttimeout->integer) { Com_Error(ERR_DROP, "Server aborted connection - the server didn't response in %is. You can try to increase the cvar cl_connecttimeout", cl_connecttimeout->integer / 1000); } else { SCR_DrawLoading(100); } } break; default: break; } }
static void UI_AbstractNodeCallDeleteTimed (uiNode_t* node, const uiCallContext_t* context) { if (UI_GetParamNumber(context) != 1) { Com_Printf("UI_AbstractNodeCallDeleteTimed: Invalid number of parameters\n"); return; } const char* msStr = UI_GetParam(context, 1); const int ms = atoi(msStr); if (ms <= 0) { UI_DeleteNode(node); } else { node->deleteTime = CL_Milliseconds() + ms; } }
/** * @brief This is called every frame, and can also be called explicitly to flush text to the screen * @sa UI_Draw * @sa CL_ViewRender * @sa SCR_DrawConsole * @sa SCR_DrawCursor */ void SCR_UpdateScreen (void) { if (cls.waitingForStart) return; /* if the screen is disabled (loading plaque is up, or vid mode changing) * do nothing at all */ if (cls.disableScreen) { if (CL_Milliseconds() - cls.disableScreen > 120000 && refdef.ready) { cls.disableScreen = 0; Com_Printf("Loading plaque timed out.\n"); return; } } /* not initialized yet */ if (!screenInitialized) return; R_BeginFrame(); /* draw scene, if it is need */ CL_ViewRender(); /* draw the ui on top of the render view */ UI_Draw(); SCR_DrawConsole(); if (cl_fps->integer) SCR_DrawString(viddef.context.width - 20 - con_fontWidth * 10, 0, va("fps: %3.1f", cls.framerate)); if (scr_rspeed->integer) { if (CL_OnBattlescape()) SCR_DrawString(viddef.context.width - 20 - con_fontWidth * 30, 80, va("brushes: %6i alias: %6i\n", refdef.brushCount, refdef.aliasCount)); else SCR_DrawString(viddef.context.width - 20 - con_fontWidth * 30, 80, va("alias: %6i\n", refdef.aliasCount)); SCR_DrawString(viddef.context.width - 20 - con_fontWidth * 30, 80 + con_fontHeight, va("batches: %6i\n", refdef.batchCount)); if (r_programs->integer) { SCR_DrawString(viddef.context.width - 20 - con_fontWidth * 30, 80 + con_fontHeight * 2, va("FFP->shader switches: %6i\n", refdef.FFPToShaderCount)); SCR_DrawString(viddef.context.width - 20 - con_fontWidth * 30, 80 + con_fontHeight * 3, va("shader->shader switches: %6i\n", refdef.shaderToShaderCount)); SCR_DrawString(viddef.context.width - 20 - con_fontWidth * 30, 80 + con_fontHeight * 4, va("shader->FFP switches: %6i\n", refdef.shaderToFFPCount)); } } SCR_DrawCursor(); R_EndFrame(); }
/** * @brief Validates the parms and queues the sound up * @param[in] origin if this is @c nullptr, the sound will be dynamically sourced from the entity * @param[in] sample The soundfile to play * @param[in] atten Attenuation of sound to be played (for example, @c fireAttenuation * or @c impactAttenuation from @c fireDef_s). * @param[in] relVolume Max mixer volume factor (0.0 - 1.0) * @sa S_StartLocalSample * @sa S_SetVolume */ void S_PlaySample (const vec3_t origin, s_sample_t* sample, float atten, float relVolume) { s_channel_t* ch; int i; float volume; if (!s_env.initialized) return; if (!sample) return; /* if the last mix of this particular sample is less than half a second ago, skip it */ if (sample->lastPlayed > CL_Milliseconds() - s_env.sampleRepeatRate) return; if ((i = S_AllocChannel()) == -1) return; sample->lastPlayed = CL_Milliseconds(); ch = &s_env.channels[i]; ch->atten = atten; ch->sample = sample; if (origin != nullptr) { VectorCopy(origin, ch->org); S_SpatializeChannel(ch); } volume = snd_volume->value * relVolume * MIX_MAX_VOLUME; Com_DPrintf(DEBUG_SOUND, "%i: Playing sample '%s' at volume %f at channel %i\n", CL_Milliseconds(), sample->name, volume, i); Mix_VolumeChunk(ch->sample->chunk, volume); Mix_PlayChannel(i, ch->sample->chunk, 0); }
/** * @brief Adds a loop sample for e.g. ambient sounds */ void S_LoopSample (const vec3_t org, s_sample_t* sample, float relVolume, float attenuation) { s_channel_t* ch; int i; if (!sample || !sample->chunk) return; ch = nullptr; for (i = 0; i < MAX_CHANNELS; i++){ /* find existing loop sound */ if (s_env.channels[i].sample == sample) { vec3_t delta; VectorSubtract(s_env.channels[i].org, org, delta); if (VectorLength(delta) < 255.0) { ch = &s_env.channels[i]; break; } } } if (ch) { /* update existing loop sample */ ch->count++; VectorMix(ch->org, org, 1.0 / ch->count, ch->org); } else { /* or allocate a new one */ float volume; if ((i = S_AllocChannel()) == -1) return; ch = &s_env.channels[i]; sample->lastPlayed = CL_Milliseconds(); VectorCopy(org, ch->org); ch->count = 1; ch->atten = attenuation; ch->sample = sample; volume = snd_volume->value * relVolume * MIX_MAX_VOLUME; Mix_VolumeChunk(ch->sample->chunk, volume); Mix_PlayChannel(i, ch->sample->chunk, 0); } S_SpatializeChannel(ch); }
/** * @brief Internal function to handle timers */ void UI_HandleTimers (void) { /* is first element is out of date? */ while (ui_firstTimer && ui_firstTimer->nextTime <= CL_Milliseconds()) { uiTimer_t *timer = ui_firstTimer; /* throw event */ timer->calledTime++; timer->callback(timer->owner, timer); /* update the sorted list */ if (timer->isRunning) { UI_RemoveTimerFromActiveList(timer); timer->nextTime += timer->delay; UI_InsertTimerInActiveList(timer->next, timer); } } }
/** * @brief Handles the catch of a @c kbutton_t state * @sa IN_KeyUp * @sa CL_GetKeyMouseState * @note Called from console callbacks with two parameters, the * key and the milliseconds when the key was released */ static void IN_KeyDown (kbutton_t * b) { int k; const char *c = Cmd_Argv(1); if (c[0]) k = atoi(c); else /* typed manually at the console for continuous down */ k = -1; /* repeating key */ if (k == b->down[0] || k == b->down[1]) return; if (!b->down[0]) b->down[0] = k; else if (!b->down[1]) b->down[1] = k; else { Com_Printf("Three keys down for a button!\n"); return; } /* still down */ if (b->state) return; /* save timestamp */ c = Cmd_Argv(2); b->downtime = atoi(c); if (!b->downtime) b->downtime = CL_Milliseconds() - 100; /* down */ b->state = 1; }
void uiEkgNode::draw (uiNode_t *node) { vec2_t size; vec2_t nodepos; const image_t *image; const char* imageName = UI_GetReferenceString(node, EXTRADATA(node).super.source); if (Q_strnull(imageName)) return; UI_GetNodeAbsPos(node, nodepos); image = UI_LoadWrappedImage(imageName); if (image) { const int ekgHeight = node->box.size[1]; const int ekgWidth = image->width; /* we have different ekg parts in each ekg image... */ const int ekgImageParts = image->height / node->box.size[1]; const int ekgMaxIndex = ekgImageParts - 1; /* we change the index of the image part in 20s steps */ /** @todo this magic number should be replaced with a sane calculation of the value */ const int ekgDivide = 20; /* If we are in the range of (ekgMaxValue + ekgDivide, ekgMaxValue) we are using the first image */ const int ekgMaxValue = ekgDivide * ekgMaxIndex; int ekgValue; float current; /** @todo these cvars should come from the script */ /* ekg_morale and ekg_hp are the node names */ if (node->name[0] == 'm') current = Cvar_GetValue("mn_morale") / EXTRADATA(node).scaleCvarValue; else current = Cvar_GetValue("mn_hp") / EXTRADATA(node).scaleCvarValue; ekgValue = std::min((int)current, ekgMaxValue); EXTRADATA(node).super.texl[1] = (ekgMaxIndex - (int)(ekgValue / ekgDivide)) * ekgHeight; EXTRADATA(node).super.texh[1] = EXTRADATA(node).super.texl[1] + ekgHeight; EXTRADATA(node).super.texl[0] = -(int) (EXTRADATA(node).scrollSpeed * CL_Milliseconds()) % ekgWidth; EXTRADATA(node).super.texh[0] = EXTRADATA(node).super.texl[0] + node->box.size[0]; /** @todo code is duplicated in the image node code */ if (node->box.size[0] && !node->box.size[1]) { const float scale = image->width / node->box.size[0]; Vector2Set(size, node->box.size[0], image->height / scale); } else if (node->box.size[1] && !node->box.size[0]) { const float scale = image->height / node->box.size[1]; Vector2Set(size, image->width / scale, node->box.size[1]); } else { if (EXTRADATA(node).super.preventRatio) { /* maximize the image into the bounding box */ const float ratio = (float) image->width / (float) image->height; if (node->box.size[1] * ratio > node->box.size[0]) { Vector2Set(size, node->box.size[0], node->box.size[0] / ratio); } else { Vector2Set(size, node->box.size[1] * ratio, node->box.size[1]); } } else { Vector2Copy(node->box.size, size); } } UI_DrawNormImage(false, nodepos[0], nodepos[1], size[0], size[1], EXTRADATA(node).super.texh[0], EXTRADATA(node).super.texh[1], EXTRADATA(node).super.texl[0], EXTRADATA(node).super.texl[1], image); } }
/** * @sa SCR_UpdateScreen * @sa SCR_EndLoadingPlaque * @sa SCR_DrawLoading */ void SCR_BeginLoadingPlaque (void) { cls.disableScreen = CL_Milliseconds(); }
static void UI_TextEntryNodeDraw (uiNode_t *node) { static const int panelTemplate[] = { CORNER_SIZE, MID_SIZE, CORNER_SIZE, CORNER_SIZE, MID_SIZE, CORNER_SIZE, MARGE }; const char *text; int texX, texY; const float *textColor; const char *image; vec2_t pos; static vec4_t disabledColor = {0.5, 0.5, 0.5, 1.0}; const char *font = UI_GetFontFromNode(node); if (node->disabled) { /** @todo need custom color when node is disabled */ textColor = disabledColor; texX = TILE_SIZE; texY = TILE_SIZE; } else if (node->state) { textColor = node->color; texX = TILE_SIZE; texY = 0; } else { textColor = node->color; texX = 0; texY = 0; } if (UI_HasFocus(node)) textColor = node->selectedColor; UI_GetNodeAbsPos(node, pos); image = UI_GetReferenceString(node, node->image); if (image) UI_DrawPanel(pos, node->size, image, texX, texY, panelTemplate); text = UI_GetReferenceString(node, node->text); if (text != NULL) { /** @todo we don't need to edit the text to draw the cursor */ if (UI_HasFocus(node)) { if (CL_Milliseconds() % 1000 < 500) { text = va("%s%c", text, CURSOR); } } if (EXTRADATA(node).isPassword) { char *c = va("%s", text); int size = UTF8_strlen(c); text = c; /* hide the text with a special char */ assert(strlen(c) >= size); /* trustable, but it can't be false */ while (size) { *c++ = HIDECHAR; size--; } /* readd the cursor */ if (UI_HasFocus(node)) { if (CL_Milliseconds() % 1000 < 500) { c--; *c++ = CURSOR; } } *c = '\0'; } if (*text != '\0') { R_Color(textColor); UI_DrawStringInBox(font, node->textalign, pos[0] + node->padding, pos[1] + node->padding, node->size[0] - node->padding - node->padding, node->size[1] - node->padding - node->padding, text, LONGLINES_PRETTYCHOP); R_Color(NULL); } } }