Added achievements system prototype

This commit is contained in:
KiritoDv 2021-05-25 21:37:33 +00:00
parent e3f11cbc43
commit 40eedb435b
12 changed files with 470 additions and 70 deletions

View File

@ -591,9 +591,10 @@ endif
CXXFLAGS := -std=c++17
LDFLAGS += -lstdc++fs
# ifeq ($(TOGGLE_GAME_DEBUG),1)
# VERSION_CFLAGS += -DTOGGLE_GAME_DEBUG
# endif
ifeq ($(DEBUG),1)
CC_CHECK += -DGAME_DEBUG
CFLAGS += -DGAME_DEBUG
endif
################################

View File

@ -32,7 +32,7 @@ const LevelScript level_intro_n64[] = {
// SLEEP(/*frames*/ 500),
LOAD_AREA(/*area*/ 1),
TRANSITION(/*transType*/ WARP_TRANSITION_FADE_FROM_COLOR, /*time*/ 20, /*color*/ 0x00, 0x00, 0x00),
SLEEP(/*frames*/ 90),
SLEEP(/*frames*/ 90),
TRANSITION(/*transType*/ WARP_TRANSITION_FADE_INTO_COLOR, /*time*/ 20, /*color*/ 0x00, 0x00, 0x00),
SLEEP(/*frames*/ 21),
CMD2A(/*unk2*/ 1),

View File

@ -14,6 +14,7 @@
#include "mario_step.h"
#include "save_file.h"
#include "thread6.h"
#include "moon/achievements/achievements.h"
#ifdef BETTERCAMERA
#include "bettercamera.h"
#endif
@ -490,6 +491,8 @@ s32 act_triple_jump(struct MarioState *m) {
play_mario_sound(m, SOUND_ACTION_TERRAIN_JUMP, SOUND_MARIO_YAHOO);
#endif
show_achievement("achievement.doATripleJump");
common_air_action_step(m, ACT_TRIPLE_JUMP_LAND, MARIO_ANIM_TRIPLE_JUMP, 0);
if (m->action == ACT_TRIPLE_JUMP_LAND) {
queue_rumble_data(5, 40);
@ -985,7 +988,7 @@ s32 act_burning_jump(struct MarioState *m) {
if (m->health < 0x100) {
m->health = 0xFF;
}
reset_rumble_timers();
return FALSE;
}

View File

@ -2,82 +2,106 @@
#include "moon/mod-engine/hooks/hook.h"
#include "moon/ui/utils/moon-draw-utils.h"
#include "moon/ui/interfaces/moon-screen.h"
#include "moon/utils/umath.h"
#include <iostream>
#include <vector>
std::map<Achievement*, bool> entries;
extern "C" {
#include "pc/cheats.h"
#include "moon/utils/moon-gfx.h"
#include "pc/platform.h"
}
namespace AchievementList {
Achievement* TRIPLE_JUMP = new Achievement("achievement.doATripleJump", "test", "Getting higher", "Do a triple jump", 0, nullptr);
struct AchievementEntry {
long long launchTime;
int state = 0;
int width = 0;
int height = 32;
bool dead = false;
};
namespace Moon {
void showAchievement(Achievement* achievement){
if(entries.find(achievement) == entries.end())
entries[achievement] = false;
}
std::map<std::string, Achievement*> registeredAchievements;
std::map<Achievement*, AchievementEntry*> entries;
void showAchievementById(Achievement* achievement){
namespace AchievementList {
Achievement* TRIPLE_JUMP = MoonAchievements::bind(new Achievement("achievement.doATripleJump", "textures/segment2/segment2.05C00.rgba16", "Getting higher", "Do a triple jump", 0, 5, nullptr));
Achievement* CHEATER = MoonAchievements::bind(new Achievement("", "textures/segment2/segment2.05C00.rgba16", "What a loser!", "Turn on the cheats", 0, 5, nullptr));
};
namespace MoonAchievements {
Achievement* bind(Achievement* achievement){
registeredAchievements[achievement->id] = achievement;
return achievement;
}
}
int w = 0;
int h = 32;
int aId = -1;
bool launched = false;
int delay = 35;
int cgid = 0;
bool cheatsGotEnabled = false;
namespace MoonInternal{
void setupAchievementEngine(std::string status){
entries[AchievementList::TRIPLE_JUMP] = false;
if(status == "Update"){
if(Cheats.EnableCheats) {
Moon::showAchievement(AchievementList::CHEATER);
cheatsGotEnabled = true;
}
}
if(status == "Init"){
Moon::registerHookListener({.hookName = HUD_DRAW, .callback = [](HookCall call){
cgid++;
int id = 0;
if(cgid > 90){
launched = true;
}
if(!launched) return;
for(auto &achievement : entries){
if(!achievement.second){
int achievementWidth = 128;
long long millis = moon_get_milliseconds();
AchievementEntry* aEntry = achievement.second;
if(aEntry->dead || achievement.second->launchTime >= millis) continue;
bool shouldClose = millis >= achievement.second->launchTime + achievement.first->duration;
if(!(gGlobalTimer % delay)){
aId++;
int aX = GetScreenWidth(false) / 2 - aEntry->width / 2;
int aY = GetScreenHeight() - aEntry->height - 20;
MoonDrawRectangle(aX, aY, aEntry->width, aEntry->height, {0, 0, 0, 150}, false);
if(!shouldClose){
if(aEntry->width >= 32)
MoonDrawTexture(GFX_DIMENSIONS_FROM_LEFT_EDGE(aX), aY, 31, 31, sys_strdup(achievement.first->icon.c_str()));
if(aEntry->width >= achievementWidth / 2){
MoonDrawText(aX + 32 + 5, aY + 2, achievement.first->title, 0.8, {255,255,255,255}, true, false);
MoonDrawText(aX + 32 + 5, aY + 16, achievement.first->description, 0.8, {255,255,255,255}, true, false);
}
switch(aId){
case 0:
if(w < 32){
w += 4;
}
break;
case 1:
if(w < 128){
w += 16;
}
delay = 60;
break;
case 2:
if(w > 0){
w -= 36;
}
break;
}
MoonDrawRectangle(GetScreenWidth(false) / 2 - w / 2, GetScreenHeight() - h - 20, w, h, {255, 255, 255, 100}, false);
if(w >= 32)
MoonDrawRectangle(GetScreenWidth(false) / 2 - w / 2, GetScreenHeight() - h - 20, 32, 32, {0, 255, 200, 100}, false);
id++;
}
aEntry->width = MathUtil::Lerp(aEntry->width, !shouldClose ? achievementWidth : 0, !shouldClose ? 0.1f : 0.35f);
aEntry->dead = shouldClose && aEntry->width <= 0;
break;
id++;
}
}});
}
}
}
namespace Moon {
void showAchievement(Achievement* achievement){
if(cheatsGotEnabled) return;
if(entries.find(achievement) != entries.end()) return;
long long time = 0;
if(entries.size() > 0)
for(auto &achievement : entries){
if(achievement.second->dead) continue;
long long now = moon_get_milliseconds();
time += (now - achievement.second->launchTime) + achievement.first->duration;
}
entries[achievement] = new AchievementEntry({.launchTime = time == 0 ? moon_get_milliseconds() + 100 : time});
}
void showAchievementById(std::string id){
if(registeredAchievements.find(id) == registeredAchievements.end()) return;
Moon::showAchievement(registeredAchievements[id]);
}
}
extern "C" {
void show_achievement(char* id){
Moon::showAchievementById(std::string(id));
}
}

View File

@ -1,22 +1,24 @@
#ifndef MoonAchievements
#define MoonAchievements
#ifdef __cplusplus
#include <string>
class Achievement {
protected:
public:
std::string id;
std::string icon;
std::string title;
std::string description;
Achievement* parent;
int points;
public:
Achievement(std::string id, std::string icon, std::string title, std::string description, int points, Achievement* parent){
long long duration;
Achievement(std::string id, std::string icon, std::string title, std::string description, int points, float duration, Achievement* parent){
this->id = id;
this->icon = icon;
this->title = title;
this->description = description;
this->duration = (long long)(duration * 1000LL);
this->parent = parent;
this->points = points;
}
@ -30,8 +32,15 @@ namespace MoonInternal{
void setupAchievementEngine(std::string status);
}
namespace MoonAchievements {
Achievement* bind(Achievement* achievement);
}
namespace AchievementList {
extern Achievement* TRIPLE_JUMP;
}
#else
void show_achievement(char* id);
#endif
#endif

View File

@ -1,22 +1,19 @@
#include "animated.h"
#include "moon/mod-engine/hooks/hook.h"
#include <sys/time.h>
#include <iostream>
#include <string>
#include <vector>
#include <map>
extern "C" {
#include "moon/utils/moon-gfx.h"
}
using json = nlohmann::json;
using namespace std;
map<string, AnimatedEntry*> textures;
long long getMilliseconds(){
struct timeval te;
gettimeofday(&te, NULL);
return te.tv_sec * 1000LL + te.tv_usec / 1000;
}
void AnimatedModifier::onInit(){
Moon::registerHookListener({.hookName = TEXTURE_BIND, .callback = [](HookCall call){
char* *hookTexture = reinterpret_cast<char**>(call.baseArgs["texture"]);
@ -25,7 +22,7 @@ void AnimatedModifier::onInit(){
AnimatedEntry* entry = textures[texName];
Frame *frame = entry->frames[entry->lastFrame];
if(getMilliseconds() >= entry->lastTime + frame->delay){
if(moon_get_milliseconds() >= entry->lastTime + frame->delay){
int maxFrames = entry->frames.size() - 1;
bool reachMax = (entry->lastFrame < maxFrames);
if(entry->bounce){
@ -36,7 +33,7 @@ void AnimatedModifier::onInit(){
}
entry->lastFrame += entry->bounce ? entry->lastBounce ? -1 : 1 : (reachMax ? 1 : -entry->lastFrame);
entry->lastTime = getMilliseconds();
entry->lastTime = moon_get_milliseconds();
frame = entry->frames[entry->lastFrame];
}

View File

@ -0,0 +1,19 @@
#include "mdebug.h"
#include "moon/achievements/achievements.h"
#include "moon/ui/widgets/mw-value.h"
#include "moon/ui/moon-ui-manager.h"
using namespace std;
extern "C" {
#include "pc/configfile.h"
#include "pc/pc_main.h"
}
MDebugCategory::MDebugCategory() : MoonCategory("Moon Debug"){
this->titleKey = false;
this->catOptions.push_back(new MWValue(22, 57 + (0 * 17), "Trigger Notification", { .btn = [](){
Moon::showAchievement(AchievementList::TRIPLE_JUMP);
}}, false));
}

View File

@ -0,0 +1,13 @@
#ifndef MoonDebugCategory
#define MoonDebugCategory
#include "mcategory.h"
#include <vector>
#include <string>
class MDebugCategory : public MoonCategory {
public:
MDebugCategory();
};
#endif

View File

@ -7,6 +7,7 @@
#include "moon/ui/screens/options/categories/mcategory.h"
#include "moon/ui/screens/options/categories/mgame.h"
#include "moon/ui/screens/options/categories/mdebug.h"
#include "moon/ui/screens/options/categories/mvideo.h"
#include "moon/ui/screens/options/categories/maudio.h"
#include "moon/ui/screens/options/categories/mcheats.h"
@ -47,6 +48,9 @@ void MoonOptMain::Init(){
void MoonOptMain::Mount(){
this->widgets.clear();
categories.push_back(new MGameCategory());
#ifdef GAME_DEBUG
categories.push_back(new MDebugCategory());
#endif
#ifdef BETTERCAMERA
categories.push_back(new MCameraCategory());
#endif

View File

@ -5,6 +5,13 @@
#include "gfx_dimensions.h"
#include "config.h"
#include "game/geo_misc.h"
#include <sys/time.h>
long long moon_get_milliseconds(){
struct timeval te;
gettimeofday(&te, NULL);
return te.tv_sec * 1000LL + te.tv_usec / 1000;
}
f32 moon_get_text_width(u8* text, float scale, u8 colored) {
f32 size = 0;

View File

@ -10,6 +10,7 @@ struct Color {
int a;
};
long long moon_get_milliseconds();
f32 moon_get_text_width(u8* text, float scale, u8 colored);
void moon_draw_colored_text(f32 x, f32 y, const u8 *str, float scale, struct Color c);
void moon_draw_text(f32 x, f32 y, const u8 *str, float scale);

322
src/moon/utils/umath.h Normal file
View File

@ -0,0 +1,322 @@
#ifndef UMATH_H
#define UMATH_H
#include <cmath>
#include <limits>
class MathUtil{
public:
inline static float Sin(float f) { return (float)sin(f); }
// Returns the cosine of angle /f/ in radians.
inline static float Cos(float f) { return (float)cos(f); }
// Returns the tangent of angle /f/ in radians.
inline static float Tan(float f) { return (float)tan(f); }
// Returns the arc-sine of /f/ - the angle in radians whose sine is /f/.
inline static float Asin(float f) { return (float)asin(f); }
// Returns the arc-cosine of /f/ - the angle in radians whose cosine is /f/.
inline static float Acos(float f) { return (float)acos(f); }
// Returns the arc-tangent of /f/ - the angle in radians whose tangent is /f/.
inline static float Atan(float f) { return (float)atan(f); }
// Returns the angle in radians whose ::ref::Tan is @@y/x@@.
inline static float Atan2(float y, float x) { return (float)atan2(y, x); }
// Returns square root of /f/.
inline static float Sqrt(float f) { return (float)sqrt(f); }
// Returns the absolute value of /f/.
inline static float Abs(float f) { return (float)abs(f); }
// Returns the absolute value of /value/.
inline static int Abs(int value) { return abs(value); }
/// *listonly*
inline static float Min(float a, float b) { return a < b ? a : b; }
// Returns the smallest of two or more values.
inline static float Min(float values[]){
int len = sizeof(values);
if (len == 0)
return 0;
float m = values[0];
for (int i = 1; i < len; i++)
{
if (values[i] < m)
m = values[i];
}
return m;
}
/// *listonly*
inline static int Min(int a, int b) { return a < b ? a : b; }
// Returns the smallest of two or more values.
inline static int Min(int values[])
{
int len = sizeof(values);
if (len == 0)
return 0;
int m = values[0];
for (int i = 1; i < len; i++)
{
if (values[i] < m)
m = values[i];
}
return m;
}
/// *listonly*
inline static float Max(float a, float b) { return a > b ? a : b; }
// Returns largest of two or more values.
inline static float Max(float values[]){
int len = sizeof(values);
if (len == 0)
return 0;
float m = values[0];
for (int i = 1; i < len; i++)
{
if (values[i] > m)
m = values[i];
}
return m;
}
/// *listonly*
inline static int Max(int a, int b) { return a > b ? a : b; }
// Returns the largest of two or more values.
inline static int Max(int values[])
{
int len = sizeof(values);
if (len == 0)
return 0;
int m = values[0];
for (int i = 1; i < len; i++)
{
if (values[i] > m)
m = values[i];
}
return m;
}
// Returns /f/ raised to power /p/.
inline static float Pow(float f, float p) { return (float)pow(f, p); }
// Returns e raised to the specified power.
inline static float Exp(float power) { return (float)exp(power); }
// Returns the natural (base e) logarithm of a specified number.
inline static float Log(float f) { return (float)log(f); }
// Returns the base 10 logarithm of a specified number.
inline static float Log10(float f) { return (float)log10(f); }
// Returns the smallest integer greater to or equal to /f/.
inline static float Ceil(float f) { return (float)ceil(f); }
// Returns the largest integer smaller to or equal to /f/.
inline static float Floor(float f) { return (float)floor(f); }
// Returns /f/ rounded to the nearest integer.
inline static float Round(float f) { return (float)round(f); }
// Returns the smallest integer greater to or equal to /f/.
inline static int CeilToInt(float f) { return (int)ceil(f); }
// Returns the largest integer smaller to or equal to /f/.
inline static int FloorToInt(float f) { return (int)floor(f); }
// Returns /f/ rounded to the nearest integer.
inline static int RoundToInt(float f) { return (int)round(f); }
// Returns the sign of /f/.
inline static float Sign(float f) { return f >= 0.0 ? 1.0 : -1.0; }
// The infamous ''3.14159265358979...'' value (RO).
const float PI = (float)PI;
// Degrees-to-radians conversion constant (RO).
const float Deg2Rad = PI * 2.0 / 360.0;
// Radians-to-degrees conversion constant (RO).
const float Rad2Deg = 1.0 / Deg2Rad;
// Clamps a value between a minimum float and maximum float value.
inline static float Clamp(float value, float min, float max)
{
if (value < min)
value = min;
else if (value > max)
value = max;
return value;
}
// Clamps value between min and max and returns value.
// Set the position of the transform to be that of the time
// but never less than 1 or more than 3
//
inline static int Clamp(int value, int min, int max)
{
if (value < min)
value = min;
else if (value > max)
value = max;
return value;
}
// Clamps value between 0 and 1 and returns value
inline static float Clamp01(float value)
{
if (value < 0.0)
return 0.0;
else if (value > 1.0)
return 1.0;
else
return value;
}
// Interpolates between /a/ and /b/ by /t/. /t/ is clamped between 0 and 1.
inline static float Lerp(float a, float b, float t)
{
return a + (b - a) * Clamp01(t);
}
// Interpolates between /a/ and /b/ by /t/ without clamping the interpolant.
inline static float LerpUnclamped(float a, float b, float t)
{
return a + (b - a) * t;
}
// Same as ::ref::Lerp but makes sure the values interpolate correctly when they wrap around 360 degrees.
inline static float LerpAngle(float a, float b, float t)
{
float delta = Repeat((b - a), 360);
if (delta > 180)
delta -= 360;
return a + delta * Clamp01(t);
}
// Moves a value /current/ towards /target/.
inline static float MoveTowards(float current, float target, float maxDelta)
{
if (abs(target - current) <= maxDelta)
return target;
return current + Sign(target - current) * maxDelta;
}
// Same as ::ref::MoveTowards but makes sure the values interpolate correctly when they wrap around 360 degrees.
inline static float MoveTowardsAngle(float current, float target, float maxDelta)
{
float deltaAngle = DeltaAngle(current, target);
if (-maxDelta < deltaAngle && deltaAngle < maxDelta)
return target;
target = current + deltaAngle;
return MoveTowards(current, target, maxDelta);
}
// Interpolates between /min/ and /max/ with smoothing at the limits.
inline static float SmoothStep(float from, float to, float t)
{
t = Clamp01(t);
t = -2.0F * t * t * t + 3.0F * t * t;
return to * t + from * (1.0 - t);
}
//*undocumented
inline static float Gamma(float value, float absmax, float gamma)
{
bool negative = value < 0.0;
float absval = Abs(value);
if (absval > absmax)
return negative ? -absval : absval;
float result = Pow(absval / absmax, gamma) * absmax;
return negative ? -result : result;
}
// Gradually changes a value towards a desired goal over time.
inline static float SmoothDamp(float current, float target, float currentVelocity, float smoothTime, float maxSpeed, float deltaTime)
{
// Based on Game Programming Gems 4 Chapter 1.10
smoothTime = Max(0.0001F, smoothTime);
float omega = 2.0 / smoothTime;
float x = omega * deltaTime;
float exp = 1.0 / (1.0 + x + 0.48F * x * x + 0.235F * x * x * x);
float change = current - target;
float originalTo = target;
// Clamp maximum speed
float maxChange = maxSpeed * smoothTime;
change = Clamp(change, -maxChange, maxChange);
target = current - change;
float temp = (currentVelocity + omega * change) * deltaTime;
currentVelocity = (currentVelocity - omega * temp) * exp;
float output = target + (change + temp) * exp;
// Prevent overshooting
if (originalTo - current > 0.0F == output > originalTo)
{
output = originalTo;
currentVelocity = (output - originalTo) / deltaTime;
}
return output;
}
inline static float SmoothDampAngle(float current, float target, float currentVelocity, float smoothTime, float maxSpeed, float deltaTime)
{
return SmoothDampAngle2(current, target, currentVelocity, smoothTime, maxSpeed, deltaTime);
}
inline static float SmoothDampAngle1(float current, float target, float currentVelocity, float smoothTime, float deltaTime)
{
float maxSpeed = (float) std::numeric_limits<double>::infinity();
return SmoothDampAngle(current, target, currentVelocity, smoothTime, maxSpeed, deltaTime);
}
// Gradually changes an angle given in degrees towards a desired goal angle over time.
inline static float SmoothDampAngle2(float current, float target, float currentVelocity, float smoothTime, float maxSpeed, float deltaTime)
{
target = current + DeltaAngle(current, target);
return SmoothDamp(current, target, currentVelocity, smoothTime, maxSpeed, deltaTime);
}
// Loops the value t, so that it is never larger than length and never smaller than 0.
inline static float Repeat(float t, float length)
{
return Clamp((float) (t - floor(t / length) * length), 0.0f, length);
}
// PingPongs the value t, so that it is never larger than length and never smaller than 0.
inline static float PingPong(float t, float length)
{
t = Repeat(t, length * 2.0);
return length - Abs(t - length);
}
// Calculates the ::ref::Lerp parameter between of two values.
inline static float InverseLerp(float a, float b, float value)
{
if (a != b)
return Clamp01((value - a) / (b - a));
else
return 0.0f;
}
// Calculates the shortest difference between two given angles.
inline static float DeltaAngle(float current, float target)
{
float delta = Repeat((target - current), 360.0F);
if (delta > 180.0F)
delta -= 360.0F;
return delta;
}
};
#endif