mirror of
https://github.com/RetroAchievements/RAIntegration.git
synced 2026-10-12 02:09:25 +00:00
Support for achievement types (#1052)
This commit is contained in:
@@ -0,0 +1,27 @@
|
||||
#ifndef MISSABLE_H
|
||||
#define MISSABLE_H
|
||||
|
||||
const uint8_t MISSABLE_PIXELS[] = {
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x23,0xae,0xa7,0x00,0x0a,0xe1,0xab,0x01,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x27,0x00,0x14,0xfe,0xf4,0x05,0x3a,0xff,0xce,0x00,0x03,0x4c,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x02,0x96,0xf8,0x38,0x00,0x56,0x6e,0x80,0x80,0x6d,0x35,0x00,0x87,0xff,0x88,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x90,0xf7,0x55,0x00,0x00,0xab,0xff,0xff,0xab,0x00,0x00,0x5d,0xf0,0x3d,0x00,0x00,0x00,
|
||||
0x00,0x0c,0x00,0x04,0x2b,0x00,0x00,0x00,0xab,0xff,0xff,0xab,0x00,0x00,0x00,0x11,0x00,0x0d,0x34,0x00,
|
||||
0x07,0xe2,0xaa,0x0f,0x00,0x00,0x00,0x00,0xab,0xff,0xff,0xab,0x00,0x00,0x00,0x00,0x21,0xeb,0xe6,0x09,
|
||||
0x3c,0xf7,0xcf,0x01,0x00,0x00,0x00,0x00,0xab,0xff,0xff,0xab,0x00,0x00,0x00,0x00,0x01,0xcb,0xc1,0x1f,
|
||||
0x00,0x18,0x31,0x00,0x00,0x00,0x00,0x00,0xab,0xff,0xff,0xab,0x00,0x00,0x00,0x00,0x00,0x11,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xab,0xff,0xff,0xab,0x00,0x00,0x00,0x00,0x00,0x02,0x40,0x46,
|
||||
0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0xab,0xff,0xff,0xab,0x00,0x00,0x00,0x00,0x00,0x02,0xff,0xfd,
|
||||
0xff,0xff,0x04,0x00,0x00,0x00,0x00,0x00,0xab,0xff,0xff,0xab,0x00,0x00,0x00,0x00,0x00,0x00,0xbc,0xb8,
|
||||
0x8d,0x89,0x08,0x00,0x00,0x00,0x00,0x00,0x72,0xab,0xab,0x72,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x45,0x5a,0x06,
|
||||
0x04,0x6a,0xb5,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc7,0xff,0x61,
|
||||
0x0a,0xe4,0xff,0x49,0x00,0x00,0x00,0x00,0x8e,0xd5,0xd5,0x8e,0x00,0x00,0x00,0x00,0x02,0x62,0xbf,0x0a,
|
||||
0x00,0x51,0x51,0x01,0x01,0x00,0x00,0x00,0xab,0xff,0xff,0xab,0x00,0x00,0x00,0x35,0x27,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x08,0xc6,0x62,0x00,0x00,0xab,0xff,0xff,0xab,0x00,0x00,0x3a,0xf5,0xdc,0x14,0x00,0x00,
|
||||
0x00,0x00,0x00,0x60,0xff,0xd8,0x08,0x19,0x6b,0x80,0x80,0x68,0x62,0x17,0x0a,0xca,0x9d,0x05,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x5d,0x33,0x00,0x83,0xff,0x81,0x00,0xaf,0xff,0x61,0x00,0x0c,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7f,0xe6,0x57,0x00,0x60,0xb2,0x47,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
};
|
||||
|
||||
#endif MISSABLE_H
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 670 B |
@@ -0,0 +1,31 @@
|
||||
#!/usr/bin/python3
|
||||
import PIL.Image as Image
|
||||
|
||||
def convert(source, output, name):
|
||||
bytes = []
|
||||
with Image.open(source, mode='r') as img:
|
||||
bytes = img.tobytes()
|
||||
|
||||
with open(output, mode='w') as f:
|
||||
f.write("#ifndef {0}_H\n".format(name));
|
||||
f.write("#define {0}_H\n\n".format(name));
|
||||
f.write("const uint8_t {0}_PIXELS[] = {{\n".format(name));
|
||||
|
||||
i = 0
|
||||
num_bytes = len(bytes)
|
||||
while i < num_bytes:
|
||||
f.write(" ")
|
||||
for j in range(0,20):
|
||||
if i < num_bytes:
|
||||
# just write the alpha value. if it's non-zero the RGB will be constant
|
||||
f.write("0x{0:02x},".format(bytes[i+3]))
|
||||
i += 4
|
||||
f.write("\n")
|
||||
|
||||
f.write("};\n\n");
|
||||
f.write("#endif {0}_H\n".format(name));
|
||||
|
||||
convert('missable.png', 'missable.h', 'MISSABLE')
|
||||
convert('progression.png', 'progression.h', 'PROGRESSION')
|
||||
convert('win-condition.png', 'win-condition.h', 'WIN_CONDITION')
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
#ifndef PROGRESSION_H
|
||||
#define PROGRESSION_H
|
||||
|
||||
const uint8_t PROGRESSION_PIXELS[] = {
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x14,0x00,0x00,0x14,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x11,0x89,0xe7,0xfa,0x17,0x17,0xfa,0xe8,0x89,0x13,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x06,0xe7,0xff,0xd6,0x7a,0x02,0x02,0x7a,0xd6,0xff,0xe8,0x41,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x01,0x84,0x58,0x01,0x00,0x00,0x00,0x00,0x01,0x5a,0xf0,0xf7,0x41,0x00,0x00,0x00,
|
||||
0x00,0x00,0x11,0x7e,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x2e,0xef,0xe7,0x13,0x00,0x00,
|
||||
0x00,0x00,0x8a,0xff,0x3c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x5a,0xff,0x87,0x00,0x00,
|
||||
0x00,0x02,0xeb,0xd5,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x0f,0x6d,0x0c,0x00,0x01,0xd6,0xea,0x02,0x00,
|
||||
0x00,0x2b,0xff,0x84,0x00,0x00,0x00,0x00,0x00,0x00,0x0f,0xc9,0xff,0x3e,0x00,0x00,0x87,0xff,0x2c,0x00,
|
||||
0x00,0x08,0x7e,0x1d,0x00,0x00,0x25,0xc2,0x3b,0x0f,0xc8,0xff,0x83,0x00,0x00,0x00,0x60,0xff,0x4a,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x25,0xf2,0xf2,0xd0,0xff,0x83,0x00,0x00,0x00,0x00,0x61,0xff,0x49,0x00,
|
||||
0x00,0x00,0x9b,0x50,0x00,0x00,0x00,0x3b,0xf2,0xff,0x83,0x00,0x00,0x00,0x00,0x00,0x87,0xff,0x2c,0x00,
|
||||
0x00,0x01,0xe9,0xd5,0x01,0x00,0x00,0x00,0x32,0x5a,0x00,0x00,0x00,0x00,0x00,0x01,0xd7,0xea,0x02,0x00,
|
||||
0x00,0x00,0x8a,0xff,0x57,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x5d,0xff,0x86,0x00,0x00,
|
||||
0x00,0x00,0x12,0xe6,0x87,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0xef,0xe6,0x12,0x00,0x00,
|
||||
0x00,0x00,0x00,0x07,0x01,0x0f,0x3e,0x01,0x00,0x00,0x00,0x00,0x01,0x5c,0xf1,0xf7,0x40,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x7f,0xff,0xd5,0x7a,0x02,0x02,0x7a,0xd7,0xff,0xe7,0x3f,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x12,0x8a,0xea,0xfa,0x17,0x17,0xfa,0xe7,0x87,0x12,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x15,0x00,0x00,0x14,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
};
|
||||
|
||||
#endif PROGRESSION_H
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 606 B |
@@ -0,0 +1,27 @@
|
||||
#ifndef WIN_CONDITION_H
|
||||
#define WIN_CONDITION_H
|
||||
|
||||
const uint8_t WIN_CONDITION_PIXELS[] = {
|
||||
0x00,0x00,0x00,0x00,0x00,0x12,0x06,0x00,0x00,0x0c,0x0c,0x00,0x00,0x06,0x12,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0xeb,0x96,0x00,0x00,0xc1,0xc1,0x00,0x00,0x96,0xeb,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0xff,0xa9,0x00,0x00,0xd4,0xd4,0x00,0x00,0xa9,0xff,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0xff,0xa9,0x00,0x00,0xd4,0xd4,0x00,0x00,0xa9,0xff,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0xff,0xa9,0x00,0x00,0xd3,0xd3,0x00,0x00,0xa9,0xff,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0xff,0xa9,0x00,0x00,0x5c,0x5c,0x00,0x00,0xa9,0xff,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0xff,0xa9,0x00,0x00,0x00,0x00,0x00,0x00,0xa9,0xff,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0xff,0xa9,0x00,0x00,0x00,0x00,0x00,0x00,0xa9,0xff,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x95,0x56,0x00,0x00,0x96,0x96,0x00,0x00,0x56,0x95,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x34,0xfe,0xfe,0x34,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xb3,0xfd,0xfd,0xb3,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x05,0x43,0x6f,0x9d,0xfe,0xa8,0xa8,0xfe,0x9d,0x6f,0x43,0x05,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x71,0xff,0xff,0xff,0xe4,0x28,0x28,0xe4,0xff,0xff,0xff,0x71,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x1b,0xdc,0xff,0x78,0x00,0x00,0x00,0x00,0x78,0xff,0xdc,0x1b,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x1c,0xdc,0xfd,0x25,0x00,0x00,0x25,0xfd,0xdc,0x1c,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x8f,0xff,0x1e,0x07,0x07,0x1e,0xff,0x8f,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0xb4,0xfa,0x6c,0xe2,0xe2,0x6c,0xfa,0xb4,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0xd8,0xff,0xff,0xe8,0xe8,0xff,0xff,0xd8,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0xdd,0xe8,0x73,0x0a,0x0a,0x73,0xe8,0xdd,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x09,0x00,0x00,0x00,0x00,0x09,0x10,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
};
|
||||
|
||||
#endif WIN_CONDITION_H
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 464 B |
@@ -145,6 +145,8 @@
|
||||
#define IDC_RA_MEMVIEWER_4 1240
|
||||
#define IDC_RA_DISPLAY_PROGRESS_INDICATOR 1241
|
||||
#define IDC_RA_MEMVIEW_32BITBE 1242
|
||||
#define IDC_RA_LBL_TYPE 1243
|
||||
#define IDC_RA_TYPE 1244
|
||||
|
||||
|
||||
#define IDD_RA_MEMORY 1501
|
||||
|
||||
+4
-2
@@ -122,9 +122,11 @@ BEGIN
|
||||
EDITTEXT IDC_RA_TITLE,50,4,214,13,ES_AUTOHSCROLL
|
||||
LTEXT "ID:",IDC_RA_LBL_ID,282,7,11,8
|
||||
EDITTEXT IDC_RA_ID,293,5,44,13,ES_AUTOHSCROLL | WS_DISABLED,WS_EX_RIGHT
|
||||
CONTROL "Active",IDC_RA_CHK_ACTIVE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,345,6,40,10
|
||||
CONTROL "Active",IDC_RA_CHK_ACTIVE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,340,6,40,10
|
||||
LTEXT "Description:",IDC_STATIC,4,23,42,8
|
||||
EDITTEXT IDC_RA_DESCRIPTION,50,21,333,13,ES_AUTOHSCROLL
|
||||
EDITTEXT IDC_RA_DESCRIPTION,50,21,287,13,ES_AUTOHSCROLL
|
||||
LTEXT "Type:",IDC_RA_LBL_TYPE,328,23,23,8
|
||||
COMBOBOX IDC_RA_TYPE,348,21,22,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
|
||||
LTEXT "Points:",IDC_RA_LBL_POINTS,4,40,23,8
|
||||
COMBOBOX IDC_RA_POINTS,50,38,42,13,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
|
||||
LTEXT "Format:",IDC_RA_LBL_FORMAT,4,40,23,8
|
||||
|
||||
@@ -27,6 +27,7 @@ public:
|
||||
unsigned int Points{ 0U };
|
||||
unsigned int Category{ 0U };
|
||||
std::string Badge;
|
||||
unsigned int Type { 0U };
|
||||
|
||||
using Callback = std::function<void(const Response& response)>;
|
||||
|
||||
|
||||
@@ -688,6 +688,7 @@ UpdateAchievement::Response ConnectedServer::UpdateAchievement(const UpdateAchie
|
||||
api_params.points = request.Points;
|
||||
api_params.category = request.Category;
|
||||
api_params.badge = request.Badge.c_str();
|
||||
api_params.type = request.Type;
|
||||
|
||||
rc_api_request_t api_request;
|
||||
if (rc_api_init_update_achievement_request(&api_request, &api_params) == RC_OK)
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
#include "AchievementModel.hh"
|
||||
|
||||
#include "RA_Log.h"
|
||||
|
||||
#include "data\context\GameContext.hh"
|
||||
|
||||
#include "data\models\LocalBadgesModel.hh"
|
||||
@@ -17,6 +19,7 @@ namespace data {
|
||||
namespace models {
|
||||
|
||||
const IntModelProperty AchievementModel::PointsProperty("AchievementModel", "Points", 5);
|
||||
const IntModelProperty AchievementModel::AchievementTypeProperty("AchievementModel", "Type", ra::etoi(ra::data::models::AchievementType::None));
|
||||
const StringModelProperty AchievementModel::BadgeProperty("AchievementModel", "Badge", L"00000");
|
||||
const BoolModelProperty AchievementModel::PauseOnResetProperty("AchievementModel", "PauseOnReset", false);
|
||||
const BoolModelProperty AchievementModel::PauseOnTriggerProperty("AchievementModel", "PauseOnTrigger", false);
|
||||
@@ -30,6 +33,7 @@ AchievementModel::AchievementModel() noexcept
|
||||
GSL_SUPPRESS_F6 SetValue(TypeProperty, ra::etoi(AssetType::Achievement));
|
||||
|
||||
SetTransactional(PointsProperty);
|
||||
SetTransactional(AchievementTypeProperty);
|
||||
SetTransactional(BadgeProperty);
|
||||
|
||||
GSL_SUPPRESS_F6 AddAssetDefinition(m_pTrigger, TriggerProperty);
|
||||
@@ -65,6 +69,11 @@ void AchievementModel::OnValueChanged(const IntModelProperty::ChangeArgs& args)
|
||||
if (m_pAchievement)
|
||||
SyncPoints();
|
||||
}
|
||||
else if (args.Property == AchievementTypeProperty)
|
||||
{
|
||||
if (m_pAchievement)
|
||||
SyncAchievementType();
|
||||
}
|
||||
else if (args.Property == IDProperty)
|
||||
{
|
||||
if (m_pAchievement)
|
||||
@@ -319,6 +328,28 @@ void AchievementModel::SyncPoints()
|
||||
m_pAchievement->public_.points = GetPoints();
|
||||
}
|
||||
|
||||
void AchievementModel::SyncAchievementType()
|
||||
{
|
||||
switch (GetAchievementType())
|
||||
{
|
||||
case ra::data::models::AchievementType::None:
|
||||
m_pAchievement->public_.type = RC_CLIENT_ACHIEVEMENT_TYPE_STANDARD;
|
||||
break;
|
||||
case ra::data::models::AchievementType::Missable:
|
||||
m_pAchievement->public_.type = RC_CLIENT_ACHIEVEMENT_TYPE_MISSABLE;
|
||||
break;
|
||||
case ra::data::models::AchievementType::Progression:
|
||||
m_pAchievement->public_.type = RC_CLIENT_ACHIEVEMENT_TYPE_PROGRESSION;
|
||||
break;
|
||||
case ra::data::models::AchievementType::Win:
|
||||
m_pAchievement->public_.type = RC_CLIENT_ACHIEVEMENT_TYPE_WIN;
|
||||
break;
|
||||
default:
|
||||
m_pAchievement->public_.type = gsl::narrow_cast<uint8_t>(GetValue(AchievementTypeProperty));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void AchievementModel::SyncCategory()
|
||||
{
|
||||
switch (GetCategory())
|
||||
@@ -421,6 +452,26 @@ void AchievementModel::Attach(struct rc_client_achievement_info_t& pAchievement,
|
||||
SetUpdatedTime(pAchievement.updated_time);
|
||||
SetTrigger(sTrigger);
|
||||
|
||||
switch (pAchievement.public_.type)
|
||||
{
|
||||
case RC_CLIENT_ACHIEVEMENT_TYPE_STANDARD:
|
||||
SetAchievementType(ra::data::models::AchievementType::None);
|
||||
break;
|
||||
case RC_CLIENT_ACHIEVEMENT_TYPE_MISSABLE:
|
||||
SetAchievementType(ra::data::models::AchievementType::Missable);
|
||||
break;
|
||||
case RC_CLIENT_ACHIEVEMENT_TYPE_PROGRESSION:
|
||||
SetAchievementType(ra::data::models::AchievementType::Progression);
|
||||
break;
|
||||
case RC_CLIENT_ACHIEVEMENT_TYPE_WIN:
|
||||
SetAchievementType(ra::data::models::AchievementType::Win);
|
||||
break;
|
||||
default:
|
||||
RA_LOG_ERR("Unsupported achievement type: %d", pAchievement.public_.type);
|
||||
SetValue(AchievementTypeProperty, pAchievement.public_.type);
|
||||
break;
|
||||
}
|
||||
|
||||
CreateServerCheckpoint();
|
||||
CreateLocalCheckpoint();
|
||||
|
||||
@@ -446,6 +497,7 @@ void AchievementModel::AttachAndInitialize(struct rc_client_achievement_info_t&
|
||||
SyncCategory();
|
||||
SyncTrigger();
|
||||
SyncState();
|
||||
SyncAchievementType();
|
||||
}
|
||||
|
||||
void AchievementModel::Serialize(ra::services::TextWriter& pWriter) const
|
||||
@@ -453,7 +505,27 @@ void AchievementModel::Serialize(ra::services::TextWriter& pWriter) const
|
||||
WriteQuoted(pWriter, GetLocalAssetDefinition(m_pTrigger));
|
||||
WritePossiblyQuoted(pWriter, GetLocalValue(NameProperty));
|
||||
WritePossiblyQuoted(pWriter, GetLocalValue(DescriptionProperty));
|
||||
pWriter.Write(":::"); // progress/max/format/author
|
||||
pWriter.Write("::"); // progress/max
|
||||
|
||||
switch (GetAchievementType())
|
||||
{
|
||||
case ra::data::models::AchievementType::None:
|
||||
WritePossiblyQuoted(pWriter, "");
|
||||
break;
|
||||
case ra::data::models::AchievementType::Missable:
|
||||
WritePossiblyQuoted(pWriter, "missable");
|
||||
break;
|
||||
case ra::data::models::AchievementType::Progression:
|
||||
WritePossiblyQuoted(pWriter, "progression");
|
||||
break;
|
||||
case ra::data::models::AchievementType::Win:
|
||||
WritePossiblyQuoted(pWriter, "win_condition");
|
||||
break;
|
||||
default:
|
||||
WriteNumber(pWriter, GetValue(TypeProperty));
|
||||
break;
|
||||
}
|
||||
|
||||
WritePossiblyQuoted(pWriter, GetLocalValue(AuthorProperty));
|
||||
WriteNumber(pWriter, GetLocalValue(PointsProperty));
|
||||
pWriter.Write("::::"); // created/modified/upvotes/downvotes
|
||||
@@ -504,9 +576,9 @@ bool AchievementModel::Deserialize(ra::Tokenizer& pTokenizer)
|
||||
if (!pTokenizer.Consume(':'))
|
||||
return false;
|
||||
|
||||
// field 7: progress format (unused)
|
||||
pTokenizer.AdvanceTo(':');
|
||||
if (!pTokenizer.Consume(':'))
|
||||
// field 7: achievement type
|
||||
std::string sType;
|
||||
if (!ReadPossiblyQuoted(pTokenizer, sType))
|
||||
return false;
|
||||
|
||||
// field 8: author (unused)
|
||||
@@ -555,6 +627,17 @@ bool AchievementModel::Deserialize(ra::Tokenizer& pTokenizer)
|
||||
SetBadge(ra::Widen(sBadge));
|
||||
SetTrigger(sTrigger);
|
||||
|
||||
if (sType.empty())
|
||||
SetAchievementType(ra::data::models::AchievementType::None);
|
||||
else if (sType == "missable")
|
||||
SetAchievementType(ra::data::models::AchievementType::Missable);
|
||||
else if (sType == "progression")
|
||||
SetAchievementType(ra::data::models::AchievementType::Progression);
|
||||
else if (sType == "win_condition")
|
||||
SetAchievementType(ra::data::models::AchievementType::Win);
|
||||
else
|
||||
SetValue(AchievementTypeProperty, atoi(sType.c_str()));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -12,6 +12,14 @@ namespace ra {
|
||||
namespace data {
|
||||
namespace models {
|
||||
|
||||
enum AchievementType
|
||||
{
|
||||
None = 0,
|
||||
Missable,
|
||||
Progression,
|
||||
Win,
|
||||
};
|
||||
|
||||
class AchievementModel : public AssetModelBase
|
||||
{
|
||||
public:
|
||||
@@ -32,6 +40,21 @@ public:
|
||||
/// </summary>
|
||||
void SetPoints(int nValue) { SetValue(PointsProperty, nValue); }
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="ModelProperty" /> for the achievement type.
|
||||
/// </summary>
|
||||
static const IntModelProperty AchievementTypeProperty;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the type of the achievement.
|
||||
/// </summary>
|
||||
AchievementType GetAchievementType() const { return ra::itoe<AchievementType>(GetValue(AchievementTypeProperty)); }
|
||||
|
||||
/// <summary>
|
||||
/// Sets the type for the achievement.
|
||||
/// </summary>
|
||||
void SetAchievementType(AchievementType nValue) { SetValue(AchievementTypeProperty, ra::etoi(nValue)); }
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="ModelProperty" /> for the badge.
|
||||
/// </summary>
|
||||
@@ -166,6 +189,7 @@ private:
|
||||
void SyncDescription();
|
||||
void SyncBadge();
|
||||
void SyncPoints();
|
||||
void SyncAchievementType();
|
||||
void SyncCategory();
|
||||
void SyncState();
|
||||
void SyncTrigger();
|
||||
|
||||
@@ -114,6 +114,8 @@ public:
|
||||
/// <param name="nAlpha">The new opacity (0.0-1.0).</param>
|
||||
virtual void SetOpacity(double fAlpha) = 0;
|
||||
|
||||
virtual void SetPixels(int nX, int nY, int nWidth, int nHeight, uint32_t* pARGB) = 0;
|
||||
|
||||
protected:
|
||||
ISurface() noexcept = default;
|
||||
};
|
||||
|
||||
@@ -76,6 +76,18 @@ static constexpr uint8_t BlendPixel(std::uint8_t nTarget, std::uint8_t nBlend, s
|
||||
return gsl::narrow_cast<std::uint8_t>(((nBlend * nAlpha) + (nTarget * (256 - nAlpha))) / 256);
|
||||
}
|
||||
|
||||
void GDIBitmapSurface::SetPixels(int nX, int nY, int nWidth, int nHeight, uint32_t* pARGB) noexcept
|
||||
{
|
||||
const auto nStride = ra::to_signed(GetWidth());
|
||||
std::uint32_t* pBits = m_pBits + gsl::narrow_cast<size_t>(nY) * nStride + nX;
|
||||
|
||||
while (nHeight--)
|
||||
{
|
||||
memcpy(pBits + gsl::narrow_cast<size_t>(nHeight) * nStride, pARGB, nWidth * sizeof(uint32_t));
|
||||
pARGB += nWidth;
|
||||
}
|
||||
}
|
||||
|
||||
void GDIBitmapSurface::WriteText(int nX, int nY, int nFont, Color nColor, const std::wstring& sText)
|
||||
{
|
||||
if (sText.empty())
|
||||
|
||||
@@ -45,6 +45,8 @@ public:
|
||||
|
||||
HBITMAP GetHBitmap() const noexcept { return m_hBitmap; }
|
||||
|
||||
void SetPixels(int nX, int nY, int nWidth, int nHeight, uint32_t* pARGB) noexcept override;
|
||||
|
||||
protected:
|
||||
std::uint32_t* m_pBits; // see note below about initializing this
|
||||
|
||||
|
||||
@@ -39,6 +39,10 @@ public:
|
||||
void DrawSurface(int nX, int nY, const ISurface& pSurface, int nSurfaceX, int nSurfaceY, int nWidth, int nHeight) noexcept override;
|
||||
|
||||
GSL_SUPPRESS_F6 void SetOpacity(_UNUSED double) override { assert("This surface does not support opacity"); }
|
||||
GSL_SUPPRESS_F6 void SetPixels(_UNUSED int, _UNUSED int, _UNUSED int, _UNUSED int, _UNUSED uint32_t*) override
|
||||
{
|
||||
assert("This surface does not support setting pixels");
|
||||
}
|
||||
|
||||
HDC GetHDC() const noexcept { return m_hDC; }
|
||||
|
||||
|
||||
@@ -46,6 +46,7 @@ const StringModelProperty AssetEditorViewModel::AssetValidationWarningProperty("
|
||||
const BoolModelProperty AssetEditorViewModel::HasMeasuredProperty("AssetEditorViewModel", "HasMeasured", false);
|
||||
const StringModelProperty AssetEditorViewModel::MeasuredValueProperty("AssetEditorViewModel", "MeasuredValue", L"[Not Active]");
|
||||
const StringModelProperty AssetEditorViewModel::WaitingLabelProperty("AssetEditorViewModel", "WaitingLabel", L"Active");
|
||||
const IntModelProperty AssetEditorViewModel::AchievementTypeProperty("AssetEditorViewModel", "AchievementType", ra::etoi(ra::data::models::AchievementType::None));
|
||||
const IntModelProperty AssetEditorViewModel::LeaderboardPartViewModel::ColorProperty("LeaderboardPartViewModel", "Color", 0);
|
||||
|
||||
AssetEditorViewModel::AssetEditorViewModel() noexcept
|
||||
@@ -54,6 +55,11 @@ AssetEditorViewModel::AssetEditorViewModel() noexcept
|
||||
|
||||
m_vmTrigger.AddNotifyTarget(*this);
|
||||
|
||||
m_vAchievementTypes.Add(ra::etoi(ra::data::models::AchievementType::None), L"");
|
||||
m_vAchievementTypes.Add(ra::etoi(ra::data::models::AchievementType::Missable), L"Missable");
|
||||
m_vAchievementTypes.Add(ra::etoi(ra::data::models::AchievementType::Progression), L"Progression");
|
||||
m_vAchievementTypes.Add(ra::etoi(ra::data::models::AchievementType::Win), L"Win");
|
||||
|
||||
m_vFormats.Add(ra::etoi(ra::data::ValueFormat::Value), L"Value");
|
||||
m_vFormats.Add(ra::etoi(ra::data::ValueFormat::Score), L"Score");
|
||||
m_vFormats.Add(ra::etoi(ra::data::ValueFormat::Frames), L"Frames");
|
||||
@@ -204,6 +210,7 @@ void AssetEditorViewModel::LoadAsset(ra::data::models::AssetModelBase* pAsset, b
|
||||
{
|
||||
SetPoints(pAchievement->GetPoints());
|
||||
SetBadge(pAchievement->GetBadge());
|
||||
SetAchievementType(pAchievement->GetAchievementType());
|
||||
SetPauseOnReset(pAchievement->IsPauseOnReset());
|
||||
SetPauseOnTrigger(pAchievement->IsPauseOnTrigger());
|
||||
|
||||
@@ -251,6 +258,7 @@ void AssetEditorViewModel::LoadAsset(ra::data::models::AssetModelBase* pAsset, b
|
||||
SetCategory(ra::itoe<ra::data::models::AssetCategory>(CategoryProperty.GetDefaultValue()));
|
||||
SetPoints(PointsProperty.GetDefaultValue());
|
||||
SetBadge(BadgeProperty.GetDefaultValue());
|
||||
SetAchievementType(ra::itoe<ra::data::models::AchievementType>(AchievementTypeProperty.GetDefaultValue()));
|
||||
SetPauseOnReset(PauseOnResetProperty.GetDefaultValue());
|
||||
SetPauseOnTrigger(PauseOnTriggerProperty.GetDefaultValue());
|
||||
SetWindowTitle(L"Achievement Editor");
|
||||
@@ -412,6 +420,8 @@ void AssetEditorViewModel::OnDataModelIntValueChanged(const IntModelProperty::Ch
|
||||
SetCategory(ra::itoe<ra::data::models::AssetCategory>(args.tNewValue));
|
||||
else if (args.Property == ra::data::models::AchievementModel::PointsProperty)
|
||||
SetPoints(args.tNewValue);
|
||||
else if (args.Property == ra::data::models::AchievementModel::TypeProperty)
|
||||
SetAchievementType(ra::itoe<ra::data::models::AchievementType>(args.tNewValue));
|
||||
else if (args.Property == ra::data::models::LeaderboardModel::ValueFormatProperty)
|
||||
SetValueFormat(ra::itoe<ra::data::ValueFormat>(args.tNewValue));
|
||||
else if (args.Property == ra::data::models::AssetModelBase::IDProperty)
|
||||
@@ -557,6 +567,8 @@ void AssetEditorViewModel::OnValueChanged(const IntModelProperty::ChangeArgs& ar
|
||||
{
|
||||
if (args.Property == PointsProperty)
|
||||
pAchievement->SetPoints(args.tNewValue);
|
||||
else if (args.Property == AchievementTypeProperty)
|
||||
pAchievement->SetAchievementType(ra::itoe<ra::data::models::AchievementType>(args.tNewValue));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include "TriggerViewModel.hh"
|
||||
|
||||
#include "data\Types.hh"
|
||||
#include "data\models\AchievementModel.hh"
|
||||
#include "data\models\AssetModelBase.hh"
|
||||
|
||||
#include "ui\WindowViewModelBase.hh"
|
||||
@@ -202,6 +203,29 @@ public:
|
||||
/// </summary>
|
||||
void SelectBadgeFile();
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="ModelProperty" /> for the achievement type.
|
||||
/// </summary>
|
||||
static const IntModelProperty AchievementTypeProperty;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the achievement type.
|
||||
/// </summary>
|
||||
ra::data::models::AchievementType GetAchievementType() const
|
||||
{
|
||||
return ra::itoe<ra::data::models::AchievementType>(GetValue(AchievementTypeProperty));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the achievement type.
|
||||
/// </summary>
|
||||
void SetAchievementType(ra::data::models::AchievementType nValue) { SetValue(AchievementTypeProperty, ra::etoi(nValue)); }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the list of achievement types.
|
||||
/// </summary>
|
||||
const LookupItemViewModelCollection& AchievementTypes() const noexcept { return m_vAchievementTypes; }
|
||||
|
||||
// ===== Leaderboard Specific =====
|
||||
|
||||
/// <summary>
|
||||
@@ -452,6 +476,7 @@ protected:
|
||||
ra::data::models::AssetModelBase* m_pAsset = nullptr;
|
||||
bool m_bIgnoreTriggerUpdate = false;
|
||||
|
||||
LookupItemViewModelCollection m_vAchievementTypes;
|
||||
LookupItemViewModelCollection m_vFormats;
|
||||
ViewModelCollection<LeaderboardPartViewModel> m_vLeaderboardParts;
|
||||
};
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
#include "RA_Defs.h"
|
||||
#include "RA_Log.h"
|
||||
|
||||
#include <rcheevos/include/rc_api_runtime.h>
|
||||
|
||||
namespace ra {
|
||||
namespace ui {
|
||||
namespace viewmodels {
|
||||
@@ -233,6 +235,25 @@ void AssetUploadViewModel::UploadAchievement(ra::data::models::AchievementModel&
|
||||
request.Points = pAchievement.GetPoints();
|
||||
request.Badge = ra::Narrow(pAchievement.GetBadge());
|
||||
|
||||
switch (pAchievement.GetAchievementType())
|
||||
{
|
||||
case ra::data::models::AchievementType::None:
|
||||
request.Type = RC_ACHIEVEMENT_TYPE_STANDARD;
|
||||
break;
|
||||
case ra::data::models::AchievementType::Missable:
|
||||
request.Type = RC_ACHIEVEMENT_TYPE_MISSABLE;
|
||||
break;
|
||||
case ra::data::models::AchievementType::Progression:
|
||||
request.Type = RC_ACHIEVEMENT_TYPE_PROGRESSION;
|
||||
break;
|
||||
case ra::data::models::AchievementType::Win:
|
||||
request.Type = RC_ACHIEVEMENT_TYPE_WIN;
|
||||
break;
|
||||
default:
|
||||
request.Type = ra::etoi(pAchievement.GetAchievementType());
|
||||
break;
|
||||
}
|
||||
|
||||
if (pAchievement.GetCategory() == ra::data::models::AssetCategory::Local)
|
||||
{
|
||||
request.Category = ra::to_unsigned(ra::etoi(ra::data::models::AssetCategory::Unofficial));
|
||||
|
||||
@@ -89,6 +89,18 @@ void OverlayAchievementsPageViewModel::Refresh()
|
||||
{
|
||||
OverlayListPageViewModel::Refresh();
|
||||
|
||||
if (m_pMissableSurface == nullptr)
|
||||
{
|
||||
#include "..\data\missable.h"
|
||||
m_pMissableSurface = LoadDecorator(MISSABLE_PIXELS, 20, 20);
|
||||
|
||||
#include "..\data\progression.h"
|
||||
m_pProgressionSurface = LoadDecorator(PROGRESSION_PIXELS, 20, 20);
|
||||
|
||||
#include "..\data\win-condition.h"
|
||||
m_pWinConditionSurface = LoadDecorator(WIN_CONDITION_PIXELS, 20, 20);
|
||||
}
|
||||
|
||||
// title
|
||||
const auto& pGameContext = ra::services::ServiceLocator::Get<ra::data::context::GameContext>();
|
||||
const auto& sTitle = pGameContext.GameTitle();
|
||||
@@ -177,6 +189,22 @@ void OverlayAchievementsPageViewModel::Refresh()
|
||||
{
|
||||
auto& pvmAchievement = GetNextItem(&nIndex);
|
||||
SetAchievement(pvmAchievement, **pAchievement);
|
||||
|
||||
switch ((*pAchievement)->type)
|
||||
{
|
||||
case RC_CLIENT_ACHIEVEMENT_TYPE_MISSABLE:
|
||||
pvmAchievement.SetDecorator(m_pMissableSurface.get());
|
||||
break;
|
||||
case RC_CLIENT_ACHIEVEMENT_TYPE_PROGRESSION:
|
||||
pvmAchievement.SetDecorator(m_pProgressionSurface.get());
|
||||
break;
|
||||
case RC_CLIENT_ACHIEVEMENT_TYPE_WIN:
|
||||
pvmAchievement.SetDecorator(m_pWinConditionSurface.get());
|
||||
break;
|
||||
default:
|
||||
pvmAchievement.SetDecorator(nullptr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -278,7 +306,7 @@ const wchar_t* OverlayAchievementsPageViewModel::GetNextButtonText() const noexc
|
||||
return L"Leaderboards";
|
||||
}
|
||||
|
||||
void OverlayAchievementsPageViewModel::RenderDetail(ra::ui::drawing::ISurface& pSurface, int nX, int nY, _UNUSED int nWidth, int nHeight) const
|
||||
void OverlayAchievementsPageViewModel::RenderDetail(ra::ui::drawing::ISurface& pSurface, int nX, int nY, int nWidth, int nHeight) const
|
||||
{
|
||||
const auto* pAchievement = m_vItems.GetItemAt(GetSelectedItemIndex());
|
||||
if (pAchievement == nullptr)
|
||||
@@ -294,12 +322,17 @@ void OverlayAchievementsPageViewModel::RenderDetail(ra::ui::drawing::ISurface& p
|
||||
|
||||
pSurface.WriteText(nX + nAchievementSize + 12, nY + 4, nFont, pTheme.ColorOverlayText(), pAchievement->GetLabel());
|
||||
pSurface.WriteText(nX + nAchievementSize + 12, nY + 4 + 26, nSubFont, pTheme.ColorOverlaySubText(), pAchievement->GetDetail());
|
||||
nY += nAchievementSize + 8;
|
||||
|
||||
const auto* pDecorator = pAchievement->GetDecorator();
|
||||
if (pDecorator != nullptr)
|
||||
pSurface.DrawSurface(nWidth - 5 - pDecorator->GetWidth(), nY + 6, *pDecorator);
|
||||
|
||||
const auto pDetail = m_vAchievementDetails.find(pAchievement->GetId());
|
||||
if (pDetail == m_vAchievementDetails.end())
|
||||
return;
|
||||
|
||||
nY += nAchievementSize + 8;
|
||||
|
||||
const auto szDetail = pSurface.MeasureText(nDetailFont, L"M");
|
||||
pSurface.WriteText(nX, nY, nDetailFont, pTheme.ColorOverlaySubText(), L"Created: " + pDetail->second.GetCreatedDate());
|
||||
nY += szDetail.Height;
|
||||
|
||||
@@ -95,6 +95,10 @@ private:
|
||||
|
||||
std::wstring m_sSummary;
|
||||
std::map<gsl::index, uint32_t> m_mHeaderKeys;
|
||||
|
||||
std::unique_ptr<ra::ui::drawing::ISurface> m_pMissableSurface;
|
||||
std::unique_ptr<ra::ui::drawing::ISurface> m_pProgressionSurface;
|
||||
std::unique_ptr<ra::ui::drawing::ISurface> m_pWinConditionSurface;
|
||||
};
|
||||
|
||||
} // namespace viewmodels
|
||||
|
||||
@@ -117,6 +117,39 @@ bool OverlayListPageViewModel::Update(double fElapsed)
|
||||
return bUpdated;
|
||||
}
|
||||
|
||||
std::unique_ptr<ra::ui::drawing::ISurface> OverlayListPageViewModel::LoadDecorator(
|
||||
const uint8_t* pixels, int nWidth, int nHeight)
|
||||
{
|
||||
uint32_t* argb_pixels = static_cast<uint32_t*>(malloc(gsl::narrow_cast<size_t>(nWidth) * nHeight * sizeof(uint32_t)));
|
||||
if (argb_pixels == nullptr)
|
||||
return nullptr;
|
||||
|
||||
const auto& pTheme = ra::services::ServiceLocator::Get<ra::ui::OverlayTheme>();
|
||||
ra::ui::Color nTextColor = pTheme.ColorOverlayDisabledText();
|
||||
|
||||
auto& pSurfaceFactory = ra::services::ServiceLocator::GetMutable<ra::ui::drawing::ISurfaceFactory>();
|
||||
auto pDecorator = pSurfaceFactory.CreateTransparentSurface(nWidth, nHeight);
|
||||
GSL_SUPPRESS_F23 uint32_t* dst = argb_pixels;
|
||||
GSL_SUPPRESS_F23 const uint8_t* src = pixels;
|
||||
const uint8_t* stop = pixels + gsl::narrow_cast<size_t>(nWidth) * nHeight;
|
||||
|
||||
while (src < stop)
|
||||
{
|
||||
nTextColor.Channel.A = *src++;
|
||||
|
||||
if (nTextColor.Channel.A == 0)
|
||||
*dst++ = 0;
|
||||
else
|
||||
*dst++ = nTextColor.ARGB;
|
||||
}
|
||||
|
||||
pDecorator->SetPixels(0, 0, nWidth, nHeight, argb_pixels);
|
||||
free(argb_pixels);
|
||||
|
||||
return pDecorator;
|
||||
}
|
||||
|
||||
|
||||
void OverlayListPageViewModel::Render(ra::ui::drawing::ISurface& pSurface, int nX, int nY, int nWidth, int nHeight) const
|
||||
{
|
||||
if (m_bDetail)
|
||||
@@ -222,6 +255,10 @@ void OverlayListPageViewModel::RenderList(ra::ui::drawing::ISurface& pSurface, i
|
||||
const auto szProgress = pSurface.MeasureText(nProgressFont, sProgress);
|
||||
pSurface.WriteText(nTextX + 12 + nProgressBarWidth + 6, nY + 1 + 26 + 25 + 4 - (szProgress.Height / 2) - 1, nProgressFont, nSubTextColor, sProgress);
|
||||
}
|
||||
|
||||
const auto* pDecorator = pItem->GetDecorator();
|
||||
if (pDecorator != nullptr)
|
||||
pSurface.DrawSurface(nWidth - 5 - pDecorator->GetWidth(), nY + 6, *pDecorator);
|
||||
}
|
||||
|
||||
nIndex++;
|
||||
|
||||
@@ -138,6 +138,12 @@ public:
|
||||
/// Gets whether the current item is a header item.
|
||||
/// </summary>
|
||||
bool IsHeader() const { return GetId() == 0; }
|
||||
|
||||
ra::ui::drawing::ISurface* GetDecorator() const noexcept { return m_pDecorator; }
|
||||
void SetDecorator(ra::ui::drawing::ISurface* pDecorator) noexcept { m_pDecorator = pDecorator; }
|
||||
|
||||
private:
|
||||
ra::ui::drawing::ISurface* m_pDecorator = nullptr;
|
||||
};
|
||||
|
||||
protected:
|
||||
@@ -157,6 +163,8 @@ protected:
|
||||
static void SetHeader(OverlayListPageViewModel::ItemViewModel& vmItem, const std::wstring& sHeader);
|
||||
static bool AssetAppearsInFilter(const ra::data::models::AssetModelBase& pAsset);
|
||||
|
||||
std::unique_ptr<ra::ui::drawing::ISurface> LoadDecorator(const uint8_t* pixels, int nWidth, int nHeight);
|
||||
|
||||
ra::ui::ViewModelCollection<ItemViewModel> m_vItems;
|
||||
|
||||
private:
|
||||
|
||||
@@ -711,6 +711,7 @@ AssetEditorDialog::AssetEditorDialog(AssetEditorViewModel& vmAssetEditor)
|
||||
m_bindBadgeImage(vmAssetEditor),
|
||||
m_bindPoints(vmAssetEditor),
|
||||
m_bindFormats(vmAssetEditor),
|
||||
m_bindAchievementTypes(vmAssetEditor),
|
||||
m_bindLeaderboardParts(vmAssetEditor),
|
||||
m_bindLowerIsBetter(vmAssetEditor),
|
||||
m_bindErrorIcon(vmAssetEditor),
|
||||
@@ -771,6 +772,10 @@ AssetEditorDialog::AssetEditorDialog(AssetEditorViewModel& vmAssetEditor)
|
||||
m_bindWindow.BindVisible(IDC_RA_BADGE_SPIN, AssetEditorViewModel::IsAchievementProperty);
|
||||
m_bindWindow.BindVisible(IDC_RA_UPLOAD_BADGE, AssetEditorViewModel::IsAchievementProperty);
|
||||
m_bindWindow.BindVisible(IDC_RA_BADGEPIC, AssetEditorViewModel::IsAchievementProperty);
|
||||
m_bindAchievementTypes.BindItems(vmAssetEditor.AchievementTypes());
|
||||
m_bindAchievementTypes.BindSelectedItem(AssetEditorViewModel::AchievementTypeProperty);
|
||||
m_bindWindow.BindVisible(IDC_RA_LBL_TYPE, AssetEditorViewModel::IsAchievementProperty);
|
||||
m_bindWindow.BindVisible(IDC_RA_TYPE, AssetEditorViewModel::IsAchievementProperty);
|
||||
|
||||
// leaderboard only fields
|
||||
m_bindFormats.BindItems(vmAssetEditor.Formats());
|
||||
@@ -940,6 +945,7 @@ BOOL AssetEditorDialog::OnInitDialog()
|
||||
m_bindPoints.SetControl(*this, IDC_RA_POINTS);
|
||||
m_bindFormats.SetControl(*this, IDC_RA_FORMAT);
|
||||
m_bindLeaderboardParts.SetControl(*this, IDC_RA_LBX_LBOARD_PARTS);
|
||||
m_bindAchievementTypes.SetControl(*this, IDC_RA_TYPE);
|
||||
|
||||
m_bindGroups.SetControl(*this, IDC_RA_LBX_GROUPS);
|
||||
m_bindConditions.SetControl(*this, IDC_RA_LBX_CONDITIONS);
|
||||
@@ -975,6 +981,8 @@ BOOL AssetEditorDialog::OnInitDialog()
|
||||
SendMessage(m_hTooltip, TTM_ACTIVATE, TRUE, 0);
|
||||
}
|
||||
|
||||
SendMessage(::GetDlgItem(GetHWND(), IDC_RA_TYPE), CB_SETDROPPEDWIDTH, 70, 0);
|
||||
|
||||
return DialogBase::OnInitDialog();
|
||||
}
|
||||
|
||||
|
||||
@@ -143,6 +143,7 @@ private:
|
||||
ra::ui::win32::bindings::ImageBinding m_bindBadgeImage;
|
||||
PointBinding m_bindPoints;
|
||||
ra::ui::win32::bindings::ComboBoxBinding m_bindFormats;
|
||||
ra::ui::win32::bindings::ComboBoxBinding m_bindAchievementTypes;
|
||||
ra::ui::win32::bindings::GridBinding m_bindLeaderboardParts;
|
||||
ra::ui::win32::bindings::CheckBoxBinding m_bindLowerIsBetter;
|
||||
|
||||
|
||||
@@ -152,6 +152,24 @@ std::wstring ToString<ra::data::models::LeaderboardModel::LeaderboardParts>(cons
|
||||
}
|
||||
}
|
||||
|
||||
template<>
|
||||
std::wstring ToString<ra::data::models::AchievementType>(const ra::data::models::AchievementType& nAchievementType)
|
||||
{
|
||||
switch (nAchievementType)
|
||||
{
|
||||
case ra::data::models::AchievementType::None:
|
||||
return L"None";
|
||||
case ra::data::models::AchievementType::Missable:
|
||||
return L"Missable";
|
||||
case ra::data::models::AchievementType::Progression:
|
||||
return L"Progression";
|
||||
case ra::data::models::AchievementType::Win:
|
||||
return L"Win";
|
||||
default:
|
||||
return std::to_wstring(static_cast<int>(nAchievementType));
|
||||
}
|
||||
}
|
||||
|
||||
#pragma warning(pop)
|
||||
|
||||
} // namespace CppUnitTestFramework
|
||||
|
||||
@@ -62,6 +62,7 @@ public:
|
||||
Assert::AreEqual(AssetState::Inactive, achievement.GetState());
|
||||
Assert::AreEqual(AssetChanges::None, achievement.GetChanges());
|
||||
Assert::AreEqual(5, achievement.GetPoints());
|
||||
Assert::AreEqual(AchievementType::None, achievement.GetAchievementType());
|
||||
Assert::AreEqual(std::wstring(L"00000"), achievement.GetBadge());
|
||||
Assert::IsFalse(achievement.IsPauseOnReset());
|
||||
Assert::IsFalse(achievement.IsPauseOnTrigger());
|
||||
|
||||
@@ -36,6 +36,7 @@ public:
|
||||
void DrawSurface(int, int, const ISurface&) noexcept override {}
|
||||
void DrawSurface(int, int, const ISurface&, int, int, int, int) noexcept override {}
|
||||
void SetOpacity(double) noexcept override {}
|
||||
void SetPixels(int, int, int, int, uint32_t*) noexcept override {}
|
||||
|
||||
private:
|
||||
unsigned int m_nWidth;
|
||||
|
||||
@@ -131,6 +131,16 @@ public:
|
||||
Assert::AreEqual((int)AssetEditorViewModel::LeaderboardPart::Start, (int)editor.GetSelectedLeaderboardPart());
|
||||
Assert::AreEqual(ra::data::ValueFormat::Value, editor.GetValueFormat());
|
||||
|
||||
Assert::AreEqual({ 4U }, editor.AchievementTypes().Count());
|
||||
Assert::AreEqual((int)ra::data::models::AchievementType::None, editor.AchievementTypes().GetItemAt(0)->GetId());
|
||||
Assert::AreEqual(std::wstring(L""), editor.AchievementTypes().GetItemAt(0)->GetLabel());
|
||||
Assert::AreEqual((int)ra::data::models::AchievementType::Missable, editor.AchievementTypes().GetItemAt(1)->GetId());
|
||||
Assert::AreEqual(std::wstring(L"Missable"), editor.AchievementTypes().GetItemAt(1)->GetLabel());
|
||||
Assert::AreEqual((int)ra::data::models::AchievementType::Progression, editor.AchievementTypes().GetItemAt(2)->GetId());
|
||||
Assert::AreEqual(std::wstring(L"Progression"), editor.AchievementTypes().GetItemAt(2)->GetLabel());
|
||||
Assert::AreEqual((int)ra::data::models::AchievementType::Win, editor.AchievementTypes().GetItemAt(3)->GetId());
|
||||
Assert::AreEqual(std::wstring(L"Win"), editor.AchievementTypes().GetItemAt(3)->GetLabel());
|
||||
|
||||
Assert::AreEqual({ 6U }, editor.Formats().Count());
|
||||
Assert::AreEqual((int)ra::data::ValueFormat::Value, editor.Formats().GetItemAt(0)->GetId());
|
||||
Assert::AreEqual(std::wstring(L"Value"), editor.Formats().GetItemAt(0)->GetLabel());
|
||||
@@ -966,6 +976,31 @@ public:
|
||||
Assert::AreEqual(50, achievement.GetPoints());
|
||||
}
|
||||
|
||||
TEST_METHOD(TestSyncAchievementType)
|
||||
{
|
||||
AssetEditorViewModelHarness editor;
|
||||
AchievementModel achievement;
|
||||
achievement.SetAchievementType(ra::data::models::AchievementType::Progression);
|
||||
achievement.CreateServerCheckpoint();
|
||||
achievement.CreateLocalCheckpoint();
|
||||
|
||||
editor.LoadAsset(&achievement);
|
||||
Assert::AreEqual(ra::data::models::AchievementType::Progression, editor.GetAchievementType());
|
||||
Assert::AreEqual(ra::data::models::AchievementType::Progression, achievement.GetAchievementType());
|
||||
|
||||
editor.SetAchievementType(ra::data::models::AchievementType::None);
|
||||
Assert::AreEqual(ra::data::models::AchievementType::None, editor.GetAchievementType());
|
||||
Assert::AreEqual(ra::data::models::AchievementType::None, achievement.GetAchievementType());
|
||||
|
||||
editor.SetAchievementType(ra::data::models::AchievementType::Win);
|
||||
Assert::AreEqual(ra::data::models::AchievementType::Win, editor.GetAchievementType());
|
||||
Assert::AreEqual(ra::data::models::AchievementType::Win, achievement.GetAchievementType());
|
||||
|
||||
editor.SetAchievementType(ra::data::models::AchievementType::Missable);
|
||||
Assert::AreEqual(ra::data::models::AchievementType::Missable, editor.GetAchievementType());
|
||||
Assert::AreEqual(ra::data::models::AchievementType::Missable, achievement.GetAchievementType());
|
||||
}
|
||||
|
||||
TEST_METHOD(TestSyncBadge)
|
||||
{
|
||||
AssetEditorViewModelHarness editor;
|
||||
|
||||
@@ -283,6 +283,46 @@ public:
|
||||
Assert::AreEqual(std::string("12345"), pRequest.Badge);
|
||||
Assert::AreEqual(3U, pRequest.Category);
|
||||
Assert::AreEqual(1U, pRequest.AchievementId);
|
||||
Assert::AreEqual(0U, pRequest.Type);
|
||||
|
||||
pResponse.AchievementId = pRequest.AchievementId;
|
||||
pResponse.Result = ra::api::ApiResult::Success;
|
||||
return true;
|
||||
});
|
||||
|
||||
vmUpload.DoUpload();
|
||||
|
||||
Assert::IsTrue(bApiCalled);
|
||||
Assert::AreEqual(AssetChanges::None, pAchievement.GetChanges());
|
||||
|
||||
vmUpload.AssertSuccess(1);
|
||||
}
|
||||
|
||||
TEST_METHOD(TestSingleCoreAchievementMissable)
|
||||
{
|
||||
AssetUploadViewModelHarness vmUpload;
|
||||
auto& pAchievement = vmUpload.AddAchievement(AssetCategory::Core, 5, L"Title1", L"Desc1", L"12345", "0xH1234=1");
|
||||
pAchievement.SetAchievementType(ra::data::models::AchievementType::Missable);
|
||||
pAchievement.UpdateLocalCheckpoint();
|
||||
Assert::AreEqual(AssetChanges::Unpublished, pAchievement.GetChanges());
|
||||
|
||||
vmUpload.QueueAsset(pAchievement);
|
||||
Assert::AreEqual({ 1U }, vmUpload.TaskCount());
|
||||
|
||||
bool bApiCalled = false;
|
||||
vmUpload.mockServer.HandleRequest<ra::api::UpdateAchievement>([&bApiCalled]
|
||||
(const ra::api::UpdateAchievement::Request& pRequest, ra::api::UpdateAchievement::Response& pResponse)
|
||||
{
|
||||
bApiCalled = true;
|
||||
Assert::AreEqual(AssetUploadViewModelHarness::GameId, pRequest.GameId);
|
||||
Assert::AreEqual(std::wstring(L"Title1"), pRequest.Title);
|
||||
Assert::AreEqual(std::wstring(L"Desc1"), pRequest.Description);
|
||||
Assert::AreEqual(std::string("0xH1234=1"), pRequest.Trigger);
|
||||
Assert::AreEqual(5U, pRequest.Points);
|
||||
Assert::AreEqual(std::string("12345"), pRequest.Badge);
|
||||
Assert::AreEqual(3U, pRequest.Category);
|
||||
Assert::AreEqual(1U, pRequest.AchievementId);
|
||||
Assert::AreEqual(1U, pRequest.Type);
|
||||
|
||||
pResponse.AchievementId = pRequest.AchievementId;
|
||||
pResponse.Result = ra::api::ApiResult::Success;
|
||||
|
||||
@@ -7,8 +7,10 @@
|
||||
#include "tests\mocks\MockGameContext.hh"
|
||||
#include "tests\mocks\MockImageRepository.hh"
|
||||
#include "tests\mocks\MockOverlayManager.hh"
|
||||
#include "tests\mocks\MockOverlayTheme.hh"
|
||||
#include "tests\mocks\MockServer.hh"
|
||||
#include "tests\mocks\MockSessionTracker.hh"
|
||||
#include "tests\mocks\MockSurface.hh"
|
||||
#include "tests\mocks\MockThreadPool.hh"
|
||||
#include "tests\mocks\MockUserContext.hh"
|
||||
#include "tests\mocks\MockWindowManager.hh"
|
||||
@@ -38,6 +40,8 @@ private:
|
||||
ra::services::mocks::MockClock mockClock;
|
||||
ra::services::mocks::MockThreadPool mockThreadPool;
|
||||
ra::ui::mocks::MockImageRepository mockImageRepository;
|
||||
ra::ui::mocks::MockOverlayTheme mockOverlayTheme;
|
||||
ra::ui::drawing::mocks::MockSurfaceFactory mockSurfaceFactory;
|
||||
ra::ui::viewmodels::mocks::MockOverlayManager mockOverlayManager;
|
||||
ra::ui::viewmodels::mocks::MockWindowManager mockWindowManager;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user