/* (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 "chat.h" #include "emoticon.h" #include #include #include #include // get_angle #include 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; UI()->ConvertMouseMove(&x, &y); m_SelectorMouse += vec2(x, y); 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 = angle(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(); UI()->MapScreen(); Graphics()->BlendNormal(); Graphics()->TextureClear(); Graphics()->QuadsBegin(); Graphics()->SetColor(0, 0, 0, 0.3f); DrawCircle(Screen.w / 2, Screen.h / 2, 190.0f, 64); Graphics()->QuadsEnd(); Graphics()->WrapClamp(); 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; Graphics()->TextureSet(GameClient()->m_EmoticonsSkin.m_SpriteEmoticons[i]); Graphics()->QuadsSetSubset(0, 0, 1, 1); Graphics()->QuadsBegin(); float NudgeX = 150.0f * cosf(Angle); float NudgeY = 150.0f * sinf(Angle); IGraphics::CQuadItem QuadItem(Screen.w / 2 + NudgeX, Screen.h / 2 + NudgeY, Size, Size); Graphics()->QuadsDraw(&QuadItem, 1); Graphics()->QuadsEnd(); } Graphics()->WrapNormal(); if(GameClient()->m_GameInfo.m_AllowEyeWheel && g_Config.m_ClEyeWheel) { Graphics()->TextureClear(); 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; 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()->TextureClear(); 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()->WrapClamp(); 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(); Graphics()->WrapNormal(); } void CEmoticon::Emote(int Emoticon) { CNetMsg_Cl_Emoticon Msg; Msg.m_Emoticon = Emoticon; Client()->SendPackMsgActive(&Msg, MSGFLAG_VITAL); if(g_Config.m_ClDummyCopyMoves) { CMsgPacker MsgDummy(NETMSGTYPE_CL_EMOTICON, false); MsgDummy.AddInt(Emoticon); Client()->SendMsg(!g_Config.m_ClDummy, &MsgDummy, MSGFLAG_VITAL); } } 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_Chat.Say(0, aBuf); }