/* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */ /* If you are missing that file, acquire a complete release at teeworlds.com. */ #include #include #include #include #include #include // get_angle #include #include #include #include "chat.h" #include "emoticon.h" CEmoticon::CEmoticon() { OnReset(); } void CEmoticon::ConKeyEmoticon(IConsole::IResult *pResult, void *pUserData) { CEmoticon *pSelf = (CEmoticon *)pUserData; if(!pSelf->m_pClient->m_Snap.m_SpecInfo.m_Active && pSelf->Client()->State() != IClient::STATE_DEMOPLAYBACK) pSelf->m_Active = pResult->GetInteger(0) != 0; } void CEmoticon::ConEmote(IConsole::IResult *pResult, void *pUserData) { ((CEmoticon *)pUserData)->Emote(pResult->GetInteger(0)); } void CEmoticon::OnConsoleInit() { Console()->Register("+emote", "", CFGFLAG_CLIENT, ConKeyEmoticon, this, "Open emote selector"); Console()->Register("emote", "i[emote-id]", CFGFLAG_CLIENT, ConEmote, this, "Use emote"); } void CEmoticon::OnReset() { m_WasActive = false; m_Active = false; m_SelectedEmote = -1; m_SelectedEyeEmote = -1; } void CEmoticon::OnRelease() { m_Active = false; } bool CEmoticon::OnMouseMove(float x, float y) { if(!m_Active) return false; #if defined(__ANDROID__) // No relative mouse on Android m_SelectorMouse = vec2(x,y); #else UI()->ConvertMouseMove(&x, &y); m_SelectorMouse += vec2(x,y); #endif return true; } void CEmoticon::DrawCircle(float x, float y, float r, int Segments) { RenderTools()->DrawCircle(x, y, r, Segments); } void CEmoticon::OnRender() { if(!m_Active) { if(m_WasActive && m_SelectedEmote != -1) Emote(m_SelectedEmote); if(m_WasActive && m_SelectedEyeEmote != -1) EyeEmote(m_SelectedEyeEmote); m_WasActive = false; return; } if(m_pClient->m_Snap.m_SpecInfo.m_Active) { m_Active = false; m_WasActive = false; return; } m_WasActive = true; if (length(m_SelectorMouse) > 170.0f) m_SelectorMouse = normalize(m_SelectorMouse) * 170.0f; float SelectedAngle = GetAngle(m_SelectorMouse) + 2*pi/24; if (SelectedAngle < 0) SelectedAngle += 2*pi; m_SelectedEmote = -1; m_SelectedEyeEmote = -1; if (length(m_SelectorMouse) > 110.0f) m_SelectedEmote = (int)(SelectedAngle / (2*pi) * NUM_EMOTICONS); else if(length(m_SelectorMouse) > 40.0f) m_SelectedEyeEmote = (int)(SelectedAngle / (2*pi) * NUM_EMOTES); CUIRect Screen = *UI()->Screen(); Graphics()->MapScreen(Screen.x, Screen.y, Screen.w, Screen.h); Graphics()->BlendNormal(); Graphics()->TextureSet(-1); Graphics()->QuadsBegin(); Graphics()->SetColor(0,0,0,0.3f); DrawCircle(Screen.w/2, Screen.h/2, 190.0f, 64); Graphics()->QuadsEnd(); Graphics()->TextureSet(g_pData->m_aImages[IMAGE_EMOTICONS].m_Id); Graphics()->QuadsBegin(); for (int i = 0; i < NUM_EMOTICONS; i++) { float Angle = 2*pi*i/NUM_EMOTICONS; if (Angle > pi) Angle -= 2*pi; bool Selected = m_SelectedEmote == i; float Size = Selected ? 80.0f : 50.0f; float NudgeX = 150.0f * cosf(Angle); float NudgeY = 150.0f * sinf(Angle); RenderTools()->SelectSprite(SPRITE_OOP + i); IGraphics::CQuadItem QuadItem(Screen.w/2 + NudgeX, Screen.h/2 + NudgeY, Size, Size); Graphics()->QuadsDraw(&QuadItem, 1); } Graphics()->QuadsEnd(); CServerInfo pServerInfo; Client()->GetServerInfo(&pServerInfo); if((IsDDRace(&pServerInfo) || IsDDNet(&pServerInfo) || IsBlockWorlds(&pServerInfo) || IsPlus(&pServerInfo)) && g_Config.m_ClEyeWheel) { Graphics()->TextureSet(-1); Graphics()->QuadsBegin(); Graphics()->SetColor(1.0,1.0,1.0,0.3f); DrawCircle(Screen.w/2, Screen.h/2, 100.0f, 64); Graphics()->QuadsEnd(); CTeeRenderInfo *pTeeInfo = &m_pClient->m_aClients[m_pClient->m_LocalIDs[g_Config.m_ClDummy]].m_RenderInfo; Graphics()->TextureSet(pTeeInfo->m_Texture); for (int i = 0; i < NUM_EMOTES; i++) { float Angle = 2*pi*i/NUM_EMOTES; if (Angle > pi) Angle -= 2*pi; bool Selected = m_SelectedEyeEmote == i; float NudgeX = 70.0f * cosf(Angle); float NudgeY = 70.0f * sinf(Angle); pTeeInfo->m_Size = Selected ? 64.0f : 48.0f; RenderTools()->RenderTee(CAnimState::GetIdle(), pTeeInfo, i, vec2(-1,0), vec2(Screen.w/2 + NudgeX, Screen.h/2 + NudgeY)); pTeeInfo->m_Size = 64.0f; } Graphics()->TextureSet(-1); Graphics()->QuadsBegin(); Graphics()->SetColor(0,0,0,0.3f); DrawCircle(Screen.w/2, Screen.h/2, 30.0f, 64); Graphics()->QuadsEnd(); } else m_SelectedEyeEmote = -1; Graphics()->TextureSet(g_pData->m_aImages[IMAGE_CURSOR].m_Id); Graphics()->QuadsBegin(); Graphics()->SetColor(1,1,1,1); IGraphics::CQuadItem QuadItem(m_SelectorMouse.x+Screen.w/2,m_SelectorMouse.y+Screen.h/2,24,24); Graphics()->QuadsDrawTL(&QuadItem, 1); Graphics()->QuadsEnd(); } void CEmoticon::Emote(int Emoticon) { CNetMsg_Cl_Emoticon Msg; Msg.m_Emoticon = Emoticon; Client()->SendPackMsg(&Msg, MSGFLAG_VITAL); if(g_Config.m_ClDummyCopyMoves) { CMsgPacker Msg(NETMSGTYPE_CL_EMOTICON); Msg.AddInt(Emoticon); Client()->SendMsgExY(&Msg, MSGFLAG_VITAL, false, !g_Config.m_ClDummy); } } void CEmoticon::EyeEmote(int Emote) { char aBuf[32]; switch(Emote) { case EMOTE_NORMAL: str_format(aBuf, sizeof(aBuf), "/emote normal %d", g_Config.m_ClEyeDuration); break; case EMOTE_PAIN: str_format(aBuf, sizeof(aBuf), "/emote pain %d", g_Config.m_ClEyeDuration); break; case EMOTE_HAPPY: str_format(aBuf, sizeof(aBuf), "/emote happy %d", g_Config.m_ClEyeDuration); break; case EMOTE_SURPRISE: str_format(aBuf, sizeof(aBuf), "/emote surprise %d", g_Config.m_ClEyeDuration); break; case EMOTE_ANGRY: str_format(aBuf, sizeof(aBuf), "/emote angry %d", g_Config.m_ClEyeDuration); break; case EMOTE_BLINK: str_format(aBuf, sizeof(aBuf), "/emote blink %d", g_Config.m_ClEyeDuration); break; } GameClient()->m_pChat->Say(0, aBuf); }