Merge branch 'dev/djui' into dev/unstable

This commit is contained in:
MysterD 2021-07-21 01:06:32 -07:00
commit 4e0a3e3e57
260 changed files with 7168 additions and 2170 deletions

View file

@ -316,7 +316,7 @@ LEVEL_DIRS := $(patsubst levels/%,%,$(dir $(wildcard levels/*/header.h)))
# Hi, I'm a PC
SRC_DIRS := src src/engine src/game src/audio src/menu src/buffers actors levels bin data assets src/pc src/pc/gfx src/pc/audio src/pc/controller src/pc/fs src/pc/fs/packtypes
SRC_DIRS += src/pc/network src/pc/network/packets src/pc/network/socket src/pc/utils
SRC_DIRS += src/pc/network src/pc/network/packets src/pc/network/socket src/pc/utils src/pc/djui
ASM_DIRS :=
#ifeq ($(DISCORDRPC),1)
@ -858,9 +858,6 @@ $(BUILD_DIR)/include/text_strings.h: include/text_strings.h.in
$(BUILD_DIR)/include/text_menu_strings.h: include/text_menu_strings.h.in
$(TEXTCONV) charmap_menu.txt $< $@
$(BUILD_DIR)/include/text_options_strings.h: include/text_options_strings.h.in
$(TEXTCONV) charmap.txt $< $@
ifeq ($(VERSION),eu)
TEXT_DIRS := text/de text/us text/fr
@ -899,7 +896,6 @@ ALL_DIRS := $(BUILD_DIR) $(addprefix $(BUILD_DIR)/,$(SRC_DIRS) $(ASM_DIRS) $(GOD
DUMMY != mkdir -p $(ALL_DIRS)
$(BUILD_DIR)/include/text_strings.h: $(BUILD_DIR)/include/text_menu_strings.h
$(BUILD_DIR)/include/text_strings.h: $(BUILD_DIR)/include/text_options_strings.h
ifeq ($(VERSION),eu)
$(BUILD_DIR)/src/menu/file_select.o: $(BUILD_DIR)/include/text_strings.h $(BUILD_DIR)/bin/eu/translation_en.o $(BUILD_DIR)/bin/eu/translation_de.o $(BUILD_DIR)/bin/eu/translation_fr.o

View file

@ -193,6 +193,7 @@ SKY_FILES := $(patsubst %.png,%.inc.c,$(wildcard $(TEXTURE_DI
MACHINE_FILES := $(patsubst %.png,%.inc.c,$(wildcard $(TEXTURE_DIR)/machine/*.png))
MOUNTAIN_FILES := $(patsubst %.png,%.inc.c,$(wildcard $(TEXTURE_DIR)/mountain/*.png))
GRASS_FILES := $(patsubst %.png,%.inc.c,$(wildcard $(TEXTURE_DIR)/grass/*.png))
CUSTOM_FONT_TITLE_FILES := $(patsubst %.png,%.inc.c,$(wildcard $(TEXTURE_DIR)/custom_font_title/*.png))
# Texture Files
$(BUILD_DIR)/bin/segment2.o: $(addprefix $(BUILD_DIR)/,$(SEGMENT2_FILES))
@ -210,6 +211,7 @@ $(BUILD_DIR)/bin/sky.o: $(addprefix $(BUILD_DIR)/,$(SKY_FILES))
$(BUILD_DIR)/bin/machine.o: $(addprefix $(BUILD_DIR)/,$(MACHINE_FILES))
$(BUILD_DIR)/bin/mountain.o: $(addprefix $(BUILD_DIR)/,$(MOUNTAIN_FILES))
$(BUILD_DIR)/bin/grass.o: $(addprefix $(BUILD_DIR)/,$(GRASS_FILES))
$(BUILD_DIR)/bin/custom_font_title.o: $(addprefix $(BUILD_DIR)/,$(CUSTOM_FONT_TITLE_FILES))
# Others
$(BUILD_DIR)/bin/segment2.elf: SEGMENT_ADDRESS := 0x02000000
@ -228,6 +230,7 @@ $(BUILD_DIR)/bin/sky.elf: SEGMENT_ADDRESS := 0x09000000
$(BUILD_DIR)/bin/machine.elf: SEGMENT_ADDRESS := 0x09000000
$(BUILD_DIR)/bin/mountain.elf: SEGMENT_ADDRESS := 0x09000000
$(BUILD_DIR)/bin/grass.elf: SEGMENT_ADDRESS := 0x09000000
$(BUILD_DIR)/bin/custom_font_title.elf: SEGMENT_ADDRESS := 0x09000000
# EU segment 19 translations
$(BUILD_DIR)/bin/eu/translation_de.elf: SEGMENT_ADDRESS := 0x19000000

499
bin/custom_font_title.c Normal file
View file

@ -0,0 +1,499 @@
#include <ultra64.h>
#include "sm64.h"
#include "game/ingame_menu.h"
#include "make_const_nonconst.h"
ALIGNED8 static const u8 texture_font_title_char_01[] = {
#include "textures/custom_font_title/custom_font_title_01.rgba32.inc.c"
};
ALIGNED8 static const u8 texture_font_title_char_02[] = {
#include "textures/custom_font_title/custom_font_title_02.rgba32.inc.c"
};
ALIGNED8 static const u8 texture_font_title_char_03[] = {
#include "textures/custom_font_title/custom_font_title_03.rgba32.inc.c"
};
ALIGNED8 static const u8 texture_font_title_char_04[] = {
#include "textures/custom_font_title/custom_font_title_04.rgba32.inc.c"
};
ALIGNED8 static const u8 texture_font_title_char_05[] = {
#include "textures/custom_font_title/custom_font_title_05.rgba32.inc.c"
};
ALIGNED8 static const u8 texture_font_title_char_06[] = {
#include "textures/custom_font_title/custom_font_title_06.rgba32.inc.c"
};
ALIGNED8 static const u8 texture_font_title_char_07[] = {
#include "textures/custom_font_title/custom_font_title_07.rgba32.inc.c"
};
ALIGNED8 static const u8 texture_font_title_char_08[] = {
#include "textures/custom_font_title/custom_font_title_08.rgba32.inc.c"
};
ALIGNED8 static const u8 texture_font_title_char_09[] = {
#include "textures/custom_font_title/custom_font_title_09.rgba32.inc.c"
};
ALIGNED8 static const u8 texture_font_title_char_10[] = {
#include "textures/custom_font_title/custom_font_title_10.rgba32.inc.c"
};
ALIGNED8 static const u8 texture_font_title_char_11[] = {
#include "textures/custom_font_title/custom_font_title_11.rgba32.inc.c"
};
ALIGNED8 static const u8 texture_font_title_char_12[] = {
#include "textures/custom_font_title/custom_font_title_12.rgba32.inc.c"
};
ALIGNED8 static const u8 texture_font_title_char_13[] = {
#include "textures/custom_font_title/custom_font_title_13.rgba32.inc.c"
};
ALIGNED8 static const u8 texture_font_title_char_14[] = {
#include "textures/custom_font_title/custom_font_title_14.rgba32.inc.c"
};
ALIGNED8 static const u8 texture_font_title_char_15[] = {
#include "textures/custom_font_title/custom_font_title_15.rgba32.inc.c"
};
ALIGNED8 static const u8 texture_font_title_char_16[] = {
#include "textures/custom_font_title/custom_font_title_16.rgba32.inc.c"
};
ALIGNED8 static const u8 texture_font_title_char_17[] = {
#include "textures/custom_font_title/custom_font_title_17.rgba32.inc.c"
};
ALIGNED8 static const u8 texture_font_title_char_18[] = {
#include "textures/custom_font_title/custom_font_title_18.rgba32.inc.c"
};
ALIGNED8 static const u8 texture_font_title_char_19[] = {
#include "textures/custom_font_title/custom_font_title_19.rgba32.inc.c"
};
ALIGNED8 static const u8 texture_font_title_char_20[] = {
#include "textures/custom_font_title/custom_font_title_20.rgba32.inc.c"
};
ALIGNED8 static const u8 texture_font_title_char_21[] = {
#include "textures/custom_font_title/custom_font_title_21.rgba32.inc.c"
};
ALIGNED8 static const u8 texture_font_title_char_22[] = {
#include "textures/custom_font_title/custom_font_title_22.rgba32.inc.c"
};
ALIGNED8 static const u8 texture_font_title_char_23[] = {
#include "textures/custom_font_title/custom_font_title_23.rgba32.inc.c"
};
ALIGNED8 static const u8 texture_font_title_char_24[] = {
#include "textures/custom_font_title/custom_font_title_24.rgba32.inc.c"
};
ALIGNED8 static const u8 texture_font_title_char_25[] = {
#include "textures/custom_font_title/custom_font_title_25.rgba32.inc.c"
};
ALIGNED8 static const u8 texture_font_title_char_26[] = {
#include "textures/custom_font_title/custom_font_title_26.rgba32.inc.c"
};
ALIGNED8 static const u8 texture_font_title_char_27[] = {
#include "textures/custom_font_title/custom_font_title_27.rgba32.inc.c"
};
ALIGNED8 static const u8 texture_font_title_char_28[] = {
#include "textures/custom_font_title/custom_font_title_28.rgba32.inc.c"
};
ALIGNED8 static const u8 texture_font_title_char_29[] = {
#include "textures/custom_font_title/custom_font_title_29.rgba32.inc.c"
};
ALIGNED8 static const u8 texture_font_title_char_30[] = {
#include "textures/custom_font_title/custom_font_title_30.rgba32.inc.c"
};
ALIGNED8 static const u8 texture_font_title_char_31[] = {
#include "textures/custom_font_title/custom_font_title_31.rgba32.inc.c"
};
ALIGNED8 static const u8 texture_font_title_char_32[] = {
#include "textures/custom_font_title/custom_font_title_32.rgba32.inc.c"
};
ALIGNED8 static const u8 texture_font_title_char_33[] = {
#include "textures/custom_font_title/custom_font_title_33.rgba32.inc.c"
};
ALIGNED8 static const u8 texture_font_title_char_34[] = {
#include "textures/custom_font_title/custom_font_title_34.rgba32.inc.c"
};
ALIGNED8 static const u8 texture_font_title_char_35[] = {
#include "textures/custom_font_title/custom_font_title_35.rgba32.inc.c"
};
ALIGNED8 static const u8 texture_font_title_char_36[] = {
#include "textures/custom_font_title/custom_font_title_36.rgba32.inc.c"
};
ALIGNED8 static const u8 texture_font_title_char_37[] = {
#include "textures/custom_font_title/custom_font_title_37.rgba32.inc.c"
};
ALIGNED8 static const u8 texture_font_title_char_38[] = {
#include "textures/custom_font_title/custom_font_title_38.rgba32.inc.c"
};
ALIGNED8 static const u8 texture_font_title_char_39[] = {
#include "textures/custom_font_title/custom_font_title_39.rgba32.inc.c"
};
ALIGNED8 static const u8 texture_font_title_char_40[] = {
#include "textures/custom_font_title/custom_font_title_40.rgba32.inc.c"
};
ALIGNED8 static const u8 texture_font_title_char_41[] = {
#include "textures/custom_font_title/custom_font_title_41.rgba32.inc.c"
};
ALIGNED8 static const u8 texture_font_title_char_42[] = {
#include "textures/custom_font_title/custom_font_title_42.rgba32.inc.c"
};
ALIGNED8 static const u8 texture_font_title_char_43[] = {
#include "textures/custom_font_title/custom_font_title_43.rgba32.inc.c"
};
ALIGNED8 static const u8 texture_font_title_char_44[] = {
#include "textures/custom_font_title/custom_font_title_44.rgba32.inc.c"
};
ALIGNED8 static const u8 texture_font_title_char_45[] = {
#include "textures/custom_font_title/custom_font_title_45.rgba32.inc.c"
};
ALIGNED8 static const u8 texture_font_title_char_46[] = {
#include "textures/custom_font_title/custom_font_title_46.rgba32.inc.c"
};
ALIGNED8 static const u8 texture_font_title_char_47[] = {
#include "textures/custom_font_title/custom_font_title_47.rgba32.inc.c"
};
ALIGNED8 static const u8 texture_font_title_char_48[] = {
#include "textures/custom_font_title/custom_font_title_48.rgba32.inc.c"
};
ALIGNED8 static const u8 texture_font_title_char_49[] = {
#include "textures/custom_font_title/custom_font_title_49.rgba32.inc.c"
};
ALIGNED8 static const u8 texture_font_title_char_50[] = {
#include "textures/custom_font_title/custom_font_title_50.rgba32.inc.c"
};
ALIGNED8 static const u8 texture_font_title_char_51[] = {
#include "textures/custom_font_title/custom_font_title_51.rgba32.inc.c"
};
ALIGNED8 static const u8 texture_font_title_char_52[] = {
#include "textures/custom_font_title/custom_font_title_52.rgba32.inc.c"
};
ALIGNED8 static const u8 texture_font_title_char_53[] = {
#include "textures/custom_font_title/custom_font_title_53.rgba32.inc.c"
};
ALIGNED8 static const u8 texture_font_title_char_54[] = {
#include "textures/custom_font_title/custom_font_title_54.rgba32.inc.c"
};
ALIGNED8 static const u8 texture_font_title_char_55[] = {
#include "textures/custom_font_title/custom_font_title_55.rgba32.inc.c"
};
ALIGNED8 static const u8 texture_font_title_char_56[] = {
#include "textures/custom_font_title/custom_font_title_56.rgba32.inc.c"
};
ALIGNED8 static const u8 texture_font_title_char_57[] = {
#include "textures/custom_font_title/custom_font_title_57.rgba32.inc.c"
};
ALIGNED8 static const u8 texture_font_title_char_58[] = {
#include "textures/custom_font_title/custom_font_title_58.rgba32.inc.c"
};
ALIGNED8 static const u8 texture_font_title_char_59[] = {
#include "textures/custom_font_title/custom_font_title_59.rgba32.inc.c"
};
ALIGNED8 static const u8 texture_font_title_char_60[] = {
#include "textures/custom_font_title/custom_font_title_60.rgba32.inc.c"
};
ALIGNED8 static const u8 texture_font_title_char_61[] = {
#include "textures/custom_font_title/custom_font_title_61.rgba32.inc.c"
};
ALIGNED8 static const u8 texture_font_title_char_62[] = {
#include "textures/custom_font_title/custom_font_title_62.rgba32.inc.c"
};
ALIGNED8 static const u8 texture_font_title_char_63[] = {
#include "textures/custom_font_title/custom_font_title_63.rgba32.inc.c"
};
ALIGNED8 static const u8 texture_font_title_char_64[] = {
#include "textures/custom_font_title/custom_font_title_64.rgba32.inc.c"
};
ALIGNED8 static const u8 texture_font_title_char_65[] = {
#include "textures/custom_font_title/custom_font_title_65.rgba32.inc.c"
};
ALIGNED8 static const u8 texture_font_title_char_66[] = {
#include "textures/custom_font_title/custom_font_title_66.rgba32.inc.c"
};
ALIGNED8 static const u8 texture_font_title_char_67[] = {
#include "textures/custom_font_title/custom_font_title_67.rgba32.inc.c"
};
ALIGNED8 static const u8 texture_font_title_char_68[] = {
#include "textures/custom_font_title/custom_font_title_68.rgba32.inc.c"
};
ALIGNED8 static const u8 texture_font_title_char_69[] = {
#include "textures/custom_font_title/custom_font_title_69.rgba32.inc.c"
};
ALIGNED8 static const u8 texture_font_title_char_70[] = {
#include "textures/custom_font_title/custom_font_title_70.rgba32.inc.c"
};
ALIGNED8 static const u8 texture_font_title_char_71[] = {
#include "textures/custom_font_title/custom_font_title_71.rgba32.inc.c"
};
ALIGNED8 static const u8 texture_font_title_char_72[] = {
#include "textures/custom_font_title/custom_font_title_72.rgba32.inc.c"
};
ALIGNED8 static const u8 texture_font_title_char_73[] = {
#include "textures/custom_font_title/custom_font_title_73.rgba32.inc.c"
};
ALIGNED8 static const u8 texture_font_title_char_74[] = {
#include "textures/custom_font_title/custom_font_title_74.rgba32.inc.c"
};
ALIGNED8 static const u8 texture_font_title_char_75[] = {
#include "textures/custom_font_title/custom_font_title_75.rgba32.inc.c"
};
ALIGNED8 static const u8 texture_font_title_char_76[] = {
#include "textures/custom_font_title/custom_font_title_76.rgba32.inc.c"
};
ALIGNED8 static const u8 texture_font_title_char_77[] = {
#include "textures/custom_font_title/custom_font_title_77.rgba32.inc.c"
};
ALIGNED8 static const u8 texture_font_title_char_78[] = {
#include "textures/custom_font_title/custom_font_title_78.rgba32.inc.c"
};
ALIGNED8 static const u8 texture_font_title_char_79[] = {
#include "textures/custom_font_title/custom_font_title_79.rgba32.inc.c"
};
ALIGNED8 static const u8 texture_font_title_char_80[] = {
#include "textures/custom_font_title/custom_font_title_80.rgba32.inc.c"
};
ALIGNED8 static const u8 texture_font_title_char_81[] = {
#include "textures/custom_font_title/custom_font_title_81.rgba32.inc.c"
};
ALIGNED8 static const u8 texture_font_title_char_82[] = {
#include "textures/custom_font_title/custom_font_title_82.rgba32.inc.c"
};
ALIGNED8 static const u8 texture_font_title_char_83[] = {
#include "textures/custom_font_title/custom_font_title_83.rgba32.inc.c"
};
ALIGNED8 static const u8 texture_font_title_char_84[] = {
#include "textures/custom_font_title/custom_font_title_84.rgba32.inc.c"
};
ALIGNED8 static const u8 texture_font_title_char_85[] = {
#include "textures/custom_font_title/custom_font_title_85.rgba32.inc.c"
};
ALIGNED8 static const u8 texture_font_title_char_86[] = {
#include "textures/custom_font_title/custom_font_title_86.rgba32.inc.c"
};
ALIGNED8 static const u8 texture_font_title_char_87[] = {
#include "textures/custom_font_title/custom_font_title_87.rgba32.inc.c"
};
ALIGNED8 static const u8 texture_font_title_char_88[] = {
#include "textures/custom_font_title/custom_font_title_88.rgba32.inc.c"
};
ALIGNED8 static const u8 texture_font_title_char_89[] = {
#include "textures/custom_font_title/custom_font_title_89.rgba32.inc.c"
};
ALIGNED8 static const u8 texture_font_title_char_90[] = {
#include "textures/custom_font_title/custom_font_title_90.rgba32.inc.c"
};
ALIGNED8 static const u8 texture_font_title_char_91[] = {
#include "textures/custom_font_title/custom_font_title_91.rgba32.inc.c"
};
ALIGNED8 static const u8 texture_font_title_char_92[] = {
#include "textures/custom_font_title/custom_font_title_92.rgba32.inc.c"
};
ALIGNED8 static const u8 texture_font_title_char_93[] = {
#include "textures/custom_font_title/custom_font_title_93.rgba32.inc.c"
};
ALIGNED8 static const u8 texture_font_title_char_94[] = {
#include "textures/custom_font_title/custom_font_title_94.rgba32.inc.c"
};
ALIGNED8 static const u8 texture_font_title_char_95[] = {
#include "textures/custom_font_title/custom_font_title_95.rgba32.inc.c"
};
const u8* const font_title_chars[] = {
texture_font_title_char_01, // !
texture_font_title_char_02, // "
texture_font_title_char_03, // #
texture_font_title_char_04, // $
texture_font_title_char_05, // %
texture_font_title_char_06, // &
texture_font_title_char_07, // '
texture_font_title_char_08, // (
texture_font_title_char_09, // )
texture_font_title_char_10, // *
texture_font_title_char_11, // +
texture_font_title_char_12, // ,
texture_font_title_char_13, // -
texture_font_title_char_14, // .
texture_font_title_char_15, // /
texture_font_title_char_16, // 0
texture_font_title_char_17, // 1
texture_font_title_char_18, // 2
texture_font_title_char_19, // 3
texture_font_title_char_20, // 4
texture_font_title_char_21, // 5
texture_font_title_char_22, // 6
texture_font_title_char_23, // 7
texture_font_title_char_24, // 8
texture_font_title_char_25, // 9
texture_font_title_char_26, // :
texture_font_title_char_27, // ;
texture_font_title_char_28, // <
texture_font_title_char_29, // =
texture_font_title_char_30, // >
texture_font_title_char_31, // ?
texture_font_title_char_32, // @
texture_font_title_char_33, // A
texture_font_title_char_34, // B
texture_font_title_char_35, // C
texture_font_title_char_36, // D
texture_font_title_char_37, // E
texture_font_title_char_38, // F
texture_font_title_char_39, // G
texture_font_title_char_40, // H
texture_font_title_char_41, // I
texture_font_title_char_42, // J
texture_font_title_char_43, // K
texture_font_title_char_44, // L
texture_font_title_char_45, // M
texture_font_title_char_46, // N
texture_font_title_char_47, // O
texture_font_title_char_48, // P
texture_font_title_char_49, // Q
texture_font_title_char_50, // R
texture_font_title_char_51, // S
texture_font_title_char_52, // T
texture_font_title_char_53, // U
texture_font_title_char_54, // V
texture_font_title_char_55, // W
texture_font_title_char_56, // X
texture_font_title_char_57, // Y
texture_font_title_char_58, // Z
texture_font_title_char_59, // [
texture_font_title_char_60, // \ //
texture_font_title_char_61, // ]
texture_font_title_char_62, // ^
texture_font_title_char_63, // _
texture_font_title_char_64, // `
texture_font_title_char_65, // a
texture_font_title_char_66, // b
texture_font_title_char_67, // c
texture_font_title_char_68, // d
texture_font_title_char_69, // e
texture_font_title_char_70, // f
texture_font_title_char_71, // g
texture_font_title_char_72, // h
texture_font_title_char_73, // i
texture_font_title_char_74, // j
texture_font_title_char_75, // k
texture_font_title_char_76, // l
texture_font_title_char_77, // m
texture_font_title_char_78, // n
texture_font_title_char_79, // o
texture_font_title_char_80, // p
texture_font_title_char_81, // q
texture_font_title_char_82, // r
texture_font_title_char_83, // s
texture_font_title_char_84, // t
texture_font_title_char_85, // u
texture_font_title_char_86, // v
texture_font_title_char_87, // w
texture_font_title_char_88, // x
texture_font_title_char_89, // y
texture_font_title_char_90, // z
texture_font_title_char_91, // {
texture_font_title_char_92, // |
texture_font_title_char_93, // }
texture_font_title_char_94, // ~
texture_font_title_char_95, // DEL
};
const f32 font_title_widths[] = {
/* ! " # $ % & ' ( ) * + , - . / */
0.50f, 0.50f, 0.50f, 0.50f, 0.50f, 0.50f, 0.50f, 0.50f, 0.50f, 0.50f, 0.50f, 0.50f, 0.50f, 0.50f, 0.50f,
/* 0 1 2 3 4 5 6 7 8 9 */
0.45f, 0.35f, 0.45f, 0.45f, 0.45f, 0.45f, 0.45f, 0.45f, 0.45f, 0.45f,
/* : ; < = > ? @ */
0.50f, 0.50f, 0.50f, 0.50f, 0.50f, 0.50f, 0.50f,
/* A B C D E F G H I J K L M N O P Q R S T U V W X Y Z */
0.55f, 0.50f, 0.50f, 0.50f, 0.45f, 0.45f, 0.50f, 0.55f, 0.28f, 0.60f, 0.50f, 0.45f, 0.55f, 0.50f, 0.50f, 0.50f, 0.50f, 0.50f, 0.55f, 0.50f, 0.50f, 0.50f, 0.60f, 0.52f, 0.60f, 0.45f,
/* [ \ ] ^ _ ` */
0.50f, 0.50f, 0.50f, 0.50f, 0.50f, 0.50f,
/* a b c d e f g h i j k l m n o p q r s t u v w x y z */
0.45f, 0.45f, 0.40f, 0.40f, 0.45f, 0.37f, 0.40f, 0.40f, 0.20f, 0.45f, 0.40f, 0.30f, 0.50f, 0.40f, 0.40f, 0.40f, 0.45f, 0.40f, 0.50f, 0.45f, 0.50f, 0.40f, 0.50f, 0.50f, 0.45f, 0.45f,
/* { | } ~ DEL */
0.50f, 0.50f, 0.50f, 0.50f, 0.50f,
};

View file

@ -3372,3 +3372,200 @@ const s16 seg2_painting_mesh_neighbor_tris[] = {
3, 240, 242, 244,
1, 243,
};
//////////////////////////////////////////////////////////
ALIGNED8 static const u8 texture_font_normal_char_03[] = {
#include "textures/segment2/custom_font_normal_char_03.ia4.inc.c"
};
ALIGNED8 static const u8 texture_font_normal_char_04[] = {
#include "textures/segment2/custom_font_normal_char_04.ia4.inc.c"
};
ALIGNED8 static const u8 texture_font_normal_char_10[] = {
#include "textures/segment2/custom_font_normal_char_10.ia4.inc.c"
};
ALIGNED8 static const u8 texture_font_normal_char_11[] = {
#include "textures/segment2/custom_font_normal_char_11.ia4.inc.c"
};
ALIGNED8 static const u8 texture_font_normal_char_15[] = {
#include "textures/segment2/custom_font_normal_char_15.ia4.inc.c"
};
ALIGNED8 static const u8 texture_font_normal_char_26[] = {
#include "textures/segment2/custom_font_normal_char_26.ia4.inc.c"
};
ALIGNED8 static const u8 texture_font_normal_char_27[] = {
#include "textures/segment2/custom_font_normal_char_27.ia4.inc.c"
};
ALIGNED8 static const u8 texture_font_normal_char_28[] = {
#include "textures/segment2/custom_font_normal_char_28.ia4.inc.c"
};
ALIGNED8 static const u8 texture_font_normal_char_29[] = {
#include "textures/segment2/custom_font_normal_char_29.ia4.inc.c"
};
ALIGNED8 static const u8 texture_font_normal_char_30[] = {
#include "textures/segment2/custom_font_normal_char_30.ia4.inc.c"
};
ALIGNED8 static const u8 texture_font_normal_char_32[] = {
#include "textures/segment2/custom_font_normal_char_32.ia4.inc.c"
};
ALIGNED8 static const u8 texture_font_normal_char_59[] = {
#include "textures/segment2/custom_font_normal_char_59.ia4.inc.c"
};
ALIGNED8 static const u8 texture_font_normal_char_60[] = {
#include "textures/segment2/custom_font_normal_char_60.ia4.inc.c"
};
ALIGNED8 static const u8 texture_font_normal_char_61[] = {
#include "textures/segment2/custom_font_normal_char_61.ia4.inc.c"
};
ALIGNED8 static const u8 texture_font_normal_char_62[] = {
#include "textures/segment2/custom_font_normal_char_62.ia4.inc.c"
};
ALIGNED8 static const u8 texture_font_normal_char_63[] = {
#include "textures/segment2/custom_font_normal_char_63.ia4.inc.c"
};
ALIGNED8 static const u8 texture_font_normal_char_64[] = {
#include "textures/segment2/custom_font_normal_char_64.ia4.inc.c"
};
ALIGNED8 static const u8 texture_font_normal_char_91[] = {
#include "textures/segment2/custom_font_normal_char_91.ia4.inc.c"
};
ALIGNED8 static const u8 texture_font_normal_char_92[] = {
#include "textures/segment2/custom_font_normal_char_92.ia4.inc.c"
};
ALIGNED8 static const u8 texture_font_normal_char_93[] = {
#include "textures/segment2/custom_font_normal_char_93.ia4.inc.c"
};
const u8* const font_normal_chars[] = {
texture_font_char_us_exclamation, // !
texture_font_char_us_double_quote_open, // "
texture_font_normal_char_03, // #
texture_font_normal_char_04, // $
texture_font_char_us_percent, // %
texture_font_char_us_ampersand, // &
texture_font_char_us_apostrophe, // '
texture_font_char_us_open_parentheses, // (
texture_font_char_us_close_parentheses, // )
texture_font_normal_char_10, // *
texture_font_normal_char_11, // +
texture_font_char_us_comma, // ,
texture_font_char_us_slash, // -
texture_font_char_us_period, // .
texture_font_normal_char_15, // /
texture_font_char_us_0, // 0
texture_font_char_us_1, // 1
texture_font_char_us_2, // 2
texture_font_char_us_3, // 3
texture_font_char_us_4, // 4
texture_font_char_us_5, // 5
texture_font_char_us_6, // 6
texture_font_char_us_7, // 7
texture_font_char_us_8, // 8
texture_font_char_us_9, // 9
texture_font_normal_char_26, // :
texture_font_normal_char_27, // ;
texture_font_normal_char_28, // <
texture_font_normal_char_29, // =
texture_font_normal_char_30, // >
texture_font_char_us_question, // ?
texture_font_normal_char_32, // @
texture_font_char_us_A, // A
texture_font_char_us_B, // B
texture_font_char_us_C, // C
texture_font_char_us_D, // D
texture_font_char_us_E, // E
texture_font_char_us_F, // F
texture_font_char_us_G, // G
texture_font_char_us_H, // H
texture_font_char_us_I, // I
texture_font_char_us_J, // J
texture_font_char_us_K, // K
texture_font_char_us_L, // L
texture_font_char_us_M, // M
texture_font_char_us_N, // N
texture_font_char_us_O, // O
texture_font_char_us_P, // P
texture_font_char_us_Q, // Q
texture_font_char_us_R, // R
texture_font_char_us_S, // S
texture_font_char_us_T, // T
texture_font_char_us_U, // U
texture_font_char_us_V, // V
texture_font_char_us_W, // W
texture_font_char_us_X, // X
texture_font_char_us_Y, // Y
texture_font_char_us_Z, // Z
texture_font_normal_char_59, // [
texture_font_normal_char_60, // \ //
texture_font_normal_char_61, // ]
texture_font_normal_char_62, // ^
texture_font_normal_char_63, // _
texture_font_normal_char_64, // `
texture_font_char_us_a, // a
texture_font_char_us_b, // b
texture_font_char_us_c, // c
texture_font_char_us_d, // d
texture_font_char_us_e, // e
texture_font_char_us_f, // f
texture_font_char_us_g, // g
texture_font_char_us_h, // h
texture_font_char_us_i, // i
texture_font_char_us_j, // j
texture_font_char_us_k, // k
texture_font_char_us_l, // l
texture_font_char_us_m, // m
texture_font_char_us_n, // n
texture_font_char_us_o, // o
texture_font_char_us_p, // p
texture_font_char_us_q, // q
texture_font_char_us_r, // r
texture_font_char_us_s, // s
texture_font_char_us_t, // t
texture_font_char_us_u, // u
texture_font_char_us_v, // v
texture_font_char_us_w, // w
texture_font_char_us_x, // x
texture_font_char_us_y, // y
texture_font_char_us_z, // z
texture_font_normal_char_91, // {
texture_font_normal_char_92, // |
texture_font_normal_char_93, // }
texture_font_char_us_tilde, // ~
texture_font_char_us_star_filled, // DEL
};
const f32 font_normal_widths[] = {
/* ! " # $ % & ' ( ) * + , - . / */
0.3125f, 0.3750f, 0.4375f, 0.3750f, 0.4375f, 0.5000f, 0.2500f, 0.3125f, 0.3125f, 0.3750f, 0.4375f, 0.2500f, 0.3750f, 0.2500f, 0.3125f,
/* 0 1 2 3 4 5 6 7 8 9 */
0.4375f, 0.4375f, 0.4375f, 0.4375f, 0.4375f, 0.4375f, 0.4375f, 0.4375f, 0.4375f, 0.4375f,
/* : ; < = > ? @ */
0.2500f, 0.2500f, 0.3125f, 0.3750f, 0.3125f, 0.4375f, 0.5750f,
/* A B C D E F G H I J K L M N O P Q R S T U V W X Y Z */
0.3750f, 0.3750f, 0.3750f, 0.3750f, 0.3750f, 0.3750f, 0.3750f, 0.3750f, 0.3125f, 0.3750f, 0.3750f, 0.3125f, 0.5000f, 0.5000f, 0.3750f, 0.3750f, 0.3750f, 0.3750f, 0.3750f, 0.3125f, 0.3750f, 0.3750f, 0.5000f, 0.4375f, 0.3750f, 0.3750f,
/* [ \ ] ^ _ ` */
0.3125f, 0.3125f, 0.3125f, 0.3750f, 0.3750f, 0.2500f,
/* a b c d e f g h i j k l m n o p q r s t u v w x y z */
0.3750f, 0.3125f, 0.3125f, 0.3750f, 0.3125f, 0.3125f, 0.3750f, 0.3125f, 0.2500f, 0.3125f, 0.3125f, 0.1875f, 0.4375f, 0.3125f, 0.3125f, 0.3125f, 0.3750f, 0.3125f, 0.3125f, 0.3125f, 0.3125f, 0.3125f, 0.4375f, 0.4375f, 0.3125f, 0.3125f,
/* { | } ~ DEL */
0.3125f, 0.2500f, 0.3125f, 0.5000f, 0.5000f
};

View file

@ -71,7 +71,7 @@
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
<IncludePath>../;../include/;../src/;$(IncludePath)</IncludePath>
<IncludePath>../;../include/;../src/;C:/msys64/mingw64/include;$(IncludePath)</IncludePath>
<OutDir>$(SolutionDir)\..\build\us_pc\</OutDir>
<TargetName>sm64.us.f3dex2e</TargetName>
</PropertyGroup>
@ -89,7 +89,7 @@
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>_DEBUG;_CONSOLE;WINSOCK;DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions>_DEBUG;_CONSOLE;WINSOCK;DEBUG;CAPI_SDL2;WAPI_SDL2;RAPI_GL;F3DEX_GBI_2;_LANGUAGE_C;BETTERCAMERA;VERSION_US;EXT_OPTIONS_MENU;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
@ -3849,7 +3849,6 @@
<ClCompile Include="..\src\game\behaviors\yoshi.inc.c" />
<ClCompile Include="..\src\game\camera.c" />
<ClCompile Include="..\src\game\characters.c" />
<ClCompile Include="..\src\game\chat.c" />
<ClCompile Include="..\src\game\debug.c" />
<ClCompile Include="..\src\game\debug_course.c" />
<ClCompile Include="..\src\game\envfx_bubbles.c" />
@ -3924,9 +3923,7 @@
<ClCompile Include="..\src\goddard\shape_helper.c" />
<ClCompile Include="..\src\goddard\skin.c" />
<ClCompile Include="..\src\goddard\skin_movement.c" />
<ClCompile Include="..\src\menu\custom_menu.c" />
<ClCompile Include="..\src\menu\file_select.c" />
<ClCompile Include="..\src\menu\custom_menu_system.c" />
<ClCompile Include="..\src\menu\intro_geo.c" />
<ClCompile Include="..\src\menu\level_select_menu.c" />
<ClCompile Include="..\src\menu\star_select.c" />
@ -3940,8 +3937,47 @@
<ClCompile Include="..\src\pc\controller\controller_keyboard.c" />
<ClCompile Include="..\src\pc\controller\controller_keyboard_debug.c" />
<ClCompile Include="..\src\pc\controller\controller_recorded_tas.c" />
<ClCompile Include="..\src\pc\controller\controller_sdl.c" />
<ClCompile Include="..\src\pc\controller\controller_sdl1.c" />
<ClCompile Include="..\src\pc\controller\controller_sdl2.c" />
<ClCompile Include="..\src\pc\discord\discordrpc.c" />
<ClCompile Include="..\src\pc\djui\djui.c" />
<ClCompile Include="..\src\pc\djui\djui_base.c" />
<ClCompile Include="..\src\pc\djui\djui_bind.c" />
<ClCompile Include="..\src\pc\djui\djui_button.c" />
<ClCompile Include="..\src\pc\djui\djui_chat_box.c" />
<ClCompile Include="..\src\pc\djui\djui_chat_message.c" />
<ClCompile Include="..\src\pc\djui\djui_checkbox.c" />
<ClCompile Include="..\src\pc\djui\djui_inputbox.c" />
<ClCompile Include="..\src\pc\djui\djui_panel_cheats.c" />
<ClCompile Include="..\src\pc\djui\djui_panel_controls.c" />
<ClCompile Include="..\src\pc\djui\djui_panel_host.c" />
<ClCompile Include="..\src\pc\djui\djui_panel_host_message.c" />
<ClCompile Include="..\src\pc\djui\djui_panel_host_save.c" />
<ClCompile Include="..\src\pc\djui\djui_panel_join.c" />
<ClCompile Include="..\src\pc\djui\djui_panel_join_message.c" />
<ClCompile Include="..\src\pc\djui\djui_panel_menu.c" />
<ClCompile Include="..\src\pc\djui\djui_panel_pause.c" />
<ClCompile Include="..\src\pc\djui\djui_popup.c" />
<ClCompile Include="..\src\pc\djui\djui_selectionbox.c" />
<ClCompile Include="..\src\pc\djui\djui_cursor.c" />
<ClCompile Include="..\src\pc\djui\djui_flow_layout.c" />
<ClCompile Include="..\src\pc\djui\djui_font.c" />
<ClCompile Include="..\src\pc\djui\djui_gfx.c" />
<ClCompile Include="..\src\pc\djui\djui_image.c" />
<ClCompile Include="..\src\pc\djui\djui_interactable.c" />
<ClCompile Include="..\src\pc\djui\djui_panel.c" />
<ClCompile Include="..\src\pc\djui\djui_panel_camera.c" />
<ClCompile Include="..\src\pc\djui\djui_panel_debug.c" />
<ClCompile Include="..\src\pc\djui\djui_panel_display.c" />
<ClCompile Include="..\src\pc\djui\djui_panel_main.c" />
<ClCompile Include="..\src\pc\djui\djui_panel_options.c" />
<ClCompile Include="..\src\pc\djui\djui_panel_confirm.c" />
<ClCompile Include="..\src\pc\djui\djui_panel_sound.c" />
<ClCompile Include="..\src\pc\djui\djui_rect.c" />
<ClCompile Include="..\src\pc\djui\djui_root.c" />
<ClCompile Include="..\src\pc\djui\djui_slider.c" />
<ClCompile Include="..\src\pc\djui\djui_text.c" />
<ClCompile Include="..\src\pc\djui\djui_three_panel.c" />
<ClCompile Include="..\src\pc\fs\dirtree.c" />
<ClCompile Include="..\src\pc\fs\fs.c" />
<ClCompile Include="..\src\pc\fs\fs_packtype_dir.c" />
@ -4008,6 +4044,8 @@
<ClCompile Include="..\src\pc\pc_main.c" />
<ClCompile Include="..\src\pc\platform.c" />
<ClCompile Include="..\src\pc\ultra_reimplementation.c" />
<ClCompile Include="..\src\pc\utils\misc.c" />
<ClCompile Include="..\src\pc\utils\string_builder.c" />
<ClCompile Include="..\src\pc\utils\string_linked_list.c" />
<ClCompile Include="..\text\define_courses.inc.c" />
<ClCompile Include="..\text\define_text.inc.c" />
@ -4347,12 +4385,49 @@
<ClInclude Include="..\include\behavior_table.h" />
<ClInclude Include="..\include\luigi_audio_defines.h" />
<ClInclude Include="..\src\game\characters.h" />
<ClInclude Include="..\src\game\chat.h" />
<ClInclude Include="..\src\game\rng_position.h" />
<ClInclude Include="..\src\menu\custom_menu.h" />
<ClInclude Include="..\src\menu\custom_menu_system.h" />
<ClInclude Include="..\src\pc\controller\controller_keyboard_debug.h" />
<ClInclude Include="..\src\pc\debuglog.h" />
<ClInclude Include="..\src\pc\djui\djui.h" />
<ClInclude Include="..\src\pc\djui\djui_base.h" />
<ClInclude Include="..\src\pc\djui\djui_bind.h" />
<ClInclude Include="..\src\pc\djui\djui_button.h" />
<ClInclude Include="..\src\pc\djui\djui_chat_box.h" />
<ClInclude Include="..\src\pc\djui\djui_chat_message.h" />
<ClInclude Include="..\src\pc\djui\djui_checkbox.h" />
<ClInclude Include="..\src\pc\djui\djui_inputbox.h" />
<ClInclude Include="..\src\pc\djui\djui_panel_cheats.h" />
<ClInclude Include="..\src\pc\djui\djui_panel_controls.h" />
<ClInclude Include="..\src\pc\djui\djui_panel_host.h" />
<ClInclude Include="..\src\pc\djui\djui_panel_host_message.h" />
<ClInclude Include="..\src\pc\djui\djui_panel_host_save.h" />
<ClInclude Include="..\src\pc\djui\djui_panel_join.h" />
<ClInclude Include="..\src\pc\djui\djui_panel_join_message.h" />
<ClInclude Include="..\src\pc\djui\djui_panel_menu.h" />
<ClInclude Include="..\src\pc\djui\djui_panel_pause.h" />
<ClInclude Include="..\src\pc\djui\djui_popup.h" />
<ClInclude Include="..\src\pc\djui\djui_selectionbox.h" />
<ClInclude Include="..\src\pc\djui\djui_cursor.h" />
<ClInclude Include="..\src\pc\djui\djui_flow_layout.h" />
<ClInclude Include="..\src\pc\djui\djui_font.h" />
<ClInclude Include="..\src\pc\djui\djui_gbi.h" />
<ClInclude Include="..\src\pc\djui\djui_gfx.h" />
<ClInclude Include="..\src\pc\djui\djui_image.h" />
<ClInclude Include="..\src\pc\djui\djui_interactable.h" />
<ClInclude Include="..\src\pc\djui\djui_panel.h" />
<ClInclude Include="..\src\pc\djui\djui_panel_camera.h" />
<ClInclude Include="..\src\pc\djui\djui_panel_debug.h" />
<ClInclude Include="..\src\pc\djui\djui_panel_display.h" />
<ClInclude Include="..\src\pc\djui\djui_panel_main.h" />
<ClInclude Include="..\src\pc\djui\djui_panel_options.h" />
<ClInclude Include="..\src\pc\djui\djui_panel_confirm.h" />
<ClInclude Include="..\src\pc\djui\djui_panel_sound.h" />
<ClInclude Include="..\src\pc\djui\djui_rect.h" />
<ClInclude Include="..\src\pc\djui\djui_root.h" />
<ClInclude Include="..\src\pc\djui\djui_slider.h" />
<ClInclude Include="..\src\pc\djui\djui_text.h" />
<ClInclude Include="..\src\pc\djui\djui_three_panel.h" />
<ClInclude Include="..\src\pc\djui\djui_types.h" />
<ClInclude Include="..\src\pc\network\branch.h" />
<ClInclude Include="..\src\pc\network\discord\activity.h" />
<ClInclude Include="..\src\pc\network\discord\discord.h" />
@ -4367,9 +4442,11 @@
<ClInclude Include="..\src\pc\network\socket\socket_linux.h" />
<ClInclude Include="..\src\pc\network\socket\socket_windows.h" />
<ClInclude Include="..\src\pc\network\version.h" />
<ClInclude Include="..\src\pc\utils\misc.h" />
<ClInclude Include="..\src\pc\utils\string_builder.h" />
<ClInclude Include="..\src\pc\utils\string_linked_list.h" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
</Project>

View file

@ -3445,6 +3445,18 @@
<Filter Include="Source Files\src\pc\network\packets\reservation-area">
<UniqueIdentifier>{9ddfaa87-399e-4f61-aae3-f91af79e14cc}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\src\pc\djui">
<UniqueIdentifier>{0e1e4798-796e-4801-be6e-69d0c3b05ad7}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\src\pc\djui\panel">
<UniqueIdentifier>{2401a619-ee3f-4637-9926-a619a5e65bcb}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\src\pc\djui\component">
<UniqueIdentifier>{471ac819-ed6b-4a33-8952-50a8e0d2d839}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\src\pc\djui\component\compound">
<UniqueIdentifier>{a7515004-4574-4bc0-9288-f716100c8a43}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\actors\amp\anims\anim_0800401C.inc.c">
@ -14805,9 +14817,6 @@
<ClCompile Include="..\src\pc\controller\controller_recorded_tas.c">
<Filter>Source Files\src\pc\controller</Filter>
</ClCompile>
<ClCompile Include="..\src\pc\controller\controller_sdl.c">
<Filter>Source Files\src\pc\controller</Filter>
</ClCompile>
<ClCompile Include="..\src\pc\discord\discordrpc.c">
<Filter>Source Files\src\pc\discord</Filter>
</ClCompile>
@ -15033,15 +15042,6 @@
<ClCompile Include="..\src\pc\network\discord\discord_network.c">
<Filter>Source Files\src\pc\network\discord</Filter>
</ClCompile>
<ClCompile Include="..\src\menu\custom_menu_system.c">
<Filter>Source Files\src\menu</Filter>
</ClCompile>
<ClCompile Include="..\src\menu\custom_menu.c">
<Filter>Source Files\src\menu</Filter>
</ClCompile>
<ClCompile Include="..\src\game\chat.c">
<Filter>Source Files\src\game</Filter>
</ClCompile>
<ClCompile Include="..\src\pc\network\packets\packet_chat.c">
<Filter>Source Files\src\pc\network\packets</Filter>
</ClCompile>
@ -15144,6 +15144,132 @@
<ClCompile Include="..\src\pc\network\packets\packet_save_set_flag.c">
<Filter>Source Files\src\pc\network\packets</Filter>
</ClCompile>
<ClCompile Include="..\src\pc\djui\djui.c">
<Filter>Source Files\src\pc\djui</Filter>
</ClCompile>
<ClCompile Include="..\src\pc\djui\djui_gfx.c">
<Filter>Source Files\src\pc\djui</Filter>
</ClCompile>
<ClCompile Include="..\src\pc\djui\djui_image.c">
<Filter>Source Files\src\pc\djui\component</Filter>
</ClCompile>
<ClCompile Include="..\src\pc\djui\djui_rect.c">
<Filter>Source Files\src\pc\djui\component</Filter>
</ClCompile>
<ClCompile Include="..\src\pc\djui\djui_text.c">
<Filter>Source Files\src\pc\djui\component</Filter>
</ClCompile>
<ClCompile Include="..\src\pc\djui\djui_base.c">
<Filter>Source Files\src\pc\djui\component</Filter>
</ClCompile>
<ClCompile Include="..\src\pc\djui\djui_root.c">
<Filter>Source Files\src\pc\djui\component</Filter>
</ClCompile>
<ClCompile Include="..\src\pc\controller\controller_sdl1.c">
<Filter>Source Files\src\pc\controller</Filter>
</ClCompile>
<ClCompile Include="..\src\pc\controller\controller_sdl2.c">
<Filter>Source Files\src\pc\controller</Filter>
</ClCompile>
<ClCompile Include="..\src\pc\djui\djui_interactable.c">
<Filter>Source Files\src\pc\djui\component</Filter>
</ClCompile>
<ClCompile Include="..\src\pc\djui\djui_flow_layout.c">
<Filter>Source Files\src\pc\djui\component\compound</Filter>
</ClCompile>
<ClCompile Include="..\src\pc\djui\djui_button.c">
<Filter>Source Files\src\pc\djui\component\compound</Filter>
</ClCompile>
<ClCompile Include="..\src\pc\djui\djui_panel_main.c">
<Filter>Source Files\src\pc\djui\panel</Filter>
</ClCompile>
<ClCompile Include="..\src\pc\utils\misc.c">
<Filter>Source Files\src\pc\utils</Filter>
</ClCompile>
<ClCompile Include="..\src\pc\djui\djui_font.c">
<Filter>Source Files\src\pc\djui</Filter>
</ClCompile>
<ClCompile Include="..\src\pc\djui\djui_panel_debug.c">
<Filter>Source Files\src\pc\djui\panel</Filter>
</ClCompile>
<ClCompile Include="..\src\pc\djui\djui_panel_options.c">
<Filter>Source Files\src\pc\djui\panel</Filter>
</ClCompile>
<ClCompile Include="..\src\pc\djui\djui_cursor.c">
<Filter>Source Files\src\pc\djui\component</Filter>
</ClCompile>
<ClCompile Include="..\src\pc\djui\djui_three_panel.c">
<Filter>Source Files\src\pc\djui\component</Filter>
</ClCompile>
<ClCompile Include="..\src\pc\djui\djui_panel_sound.c">
<Filter>Source Files\src\pc\djui\panel</Filter>
</ClCompile>
<ClCompile Include="..\src\pc\djui\djui_panel.c">
<Filter>Source Files\src\pc\djui\panel</Filter>
</ClCompile>
<ClCompile Include="..\src\pc\djui\djui_slider.c">
<Filter>Source Files\src\pc\djui\component\compound</Filter>
</ClCompile>
<ClCompile Include="..\src\pc\djui\djui_panel_camera.c">
<Filter>Source Files\src\pc\djui\panel</Filter>
</ClCompile>
<ClCompile Include="..\src\pc\djui\djui_checkbox.c">
<Filter>Source Files\src\pc\djui\component\compound</Filter>
</ClCompile>
<ClCompile Include="..\src\pc\djui\djui_panel_display.c">
<Filter>Source Files\src\pc\djui\panel</Filter>
</ClCompile>
<ClCompile Include="..\src\pc\djui\djui_selectionbox.c">
<Filter>Source Files\src\pc\djui\component\compound</Filter>
</ClCompile>
<ClCompile Include="..\src\pc\djui\djui_panel_controls.c">
<Filter>Source Files\src\pc\djui\panel</Filter>
</ClCompile>
<ClCompile Include="..\src\pc\djui\djui_bind.c">
<Filter>Source Files\src\pc\djui\component\compound</Filter>
</ClCompile>
<ClCompile Include="..\src\pc\djui\djui_panel_host.c">
<Filter>Source Files\src\pc\djui\panel</Filter>
</ClCompile>
<ClCompile Include="..\src\pc\djui\djui_panel_menu.c">
<Filter>Source Files\src\pc\djui\panel</Filter>
</ClCompile>
<ClCompile Include="..\src\pc\djui\djui_panel_host_message.c">
<Filter>Source Files\src\pc\djui\panel</Filter>
</ClCompile>
<ClCompile Include="..\src\pc\djui\djui_inputbox.c">
<Filter>Source Files\src\pc\djui\component\compound</Filter>
</ClCompile>
<ClCompile Include="..\src\pc\djui\djui_panel_join.c">
<Filter>Source Files\src\pc\djui\panel</Filter>
</ClCompile>
<ClCompile Include="..\src\pc\djui\djui_panel_join_message.c">
<Filter>Source Files\src\pc\djui\panel</Filter>
</ClCompile>
<ClCompile Include="..\src\pc\utils\string_builder.c">
<Filter>Source Files\src\pc\utils</Filter>
</ClCompile>
<ClCompile Include="..\src\pc\djui\djui_popup.c">
<Filter>Source Files\src\pc\djui\component\compound</Filter>
</ClCompile>
<ClCompile Include="..\src\pc\djui\djui_panel_host_save.c">
<Filter>Source Files\src\pc\djui\panel</Filter>
</ClCompile>
<ClCompile Include="..\src\pc\djui\djui_panel_confirm.c">
<Filter>Source Files\src\pc\djui\panel</Filter>
</ClCompile>
<ClCompile Include="..\src\pc\djui\djui_panel_pause.c">
<Filter>Source Files\src\pc\djui\panel</Filter>
</ClCompile>
<ClCompile Include="..\src\pc\djui\djui_panel_cheats.c">
<Filter>Source Files\src\pc\djui\panel</Filter>
</ClCompile>
<ClCompile Include="..\src\pc\djui\djui_chat_box.c">
<Filter>Source Files\src\pc\djui\component</Filter>
</ClCompile>
<ClCompile Include="..\src\pc\djui\djui_chat_message.c">
<Filter>Source Files\src\pc\djui\component\compound</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\actors\common0.h">
@ -16084,15 +16210,6 @@
<ClInclude Include="..\src\pc\network\discord\discord_network.h">
<Filter>Header Files\src\pc\network\discord</Filter>
</ClInclude>
<ClInclude Include="..\src\menu\custom_menu_system.h">
<Filter>Header Files\src\menu</Filter>
</ClInclude>
<ClInclude Include="..\src\menu\custom_menu.h">
<Filter>Header Files\src\menu</Filter>
</ClInclude>
<ClInclude Include="..\src\game\chat.h">
<Filter>Header Files\src\game</Filter>
</ClInclude>
<ClInclude Include="..\src\pc\network\network_player.h">
<Filter>Header Files\src\pc\network</Filter>
</ClInclude>
@ -16117,5 +16234,131 @@
<ClInclude Include="..\src\pc\network\reservation_area.h">
<Filter>Header Files\src\pc\network</Filter>
</ClInclude>
<ClInclude Include="..\src\pc\djui\djui.h">
<Filter>Source Files\src\pc\djui</Filter>
</ClInclude>
<ClInclude Include="..\src\pc\djui\djui_gfx.h">
<Filter>Source Files\src\pc\djui</Filter>
</ClInclude>
<ClInclude Include="..\src\pc\djui\djui_types.h">
<Filter>Source Files\src\pc\djui</Filter>
</ClInclude>
<ClInclude Include="..\src\pc\djui\djui_gbi.h">
<Filter>Source Files\src\pc\djui</Filter>
</ClInclude>
<ClInclude Include="..\src\pc\djui\djui_image.h">
<Filter>Source Files\src\pc\djui\component</Filter>
</ClInclude>
<ClInclude Include="..\src\pc\djui\djui_rect.h">
<Filter>Source Files\src\pc\djui\component</Filter>
</ClInclude>
<ClInclude Include="..\src\pc\djui\djui_text.h">
<Filter>Source Files\src\pc\djui\component</Filter>
</ClInclude>
<ClInclude Include="..\src\pc\djui\djui_base.h">
<Filter>Source Files\src\pc\djui\component</Filter>
</ClInclude>
<ClInclude Include="..\src\pc\djui\djui_root.h">
<Filter>Source Files\src\pc\djui\component</Filter>
</ClInclude>
<ClInclude Include="..\src\pc\djui\djui_interactable.h">
<Filter>Source Files\src\pc\djui\component</Filter>
</ClInclude>
<ClInclude Include="..\src\pc\djui\djui_flow_layout.h">
<Filter>Source Files\src\pc\djui\component\compound</Filter>
</ClInclude>
<ClInclude Include="..\src\pc\djui\djui_button.h">
<Filter>Source Files\src\pc\djui\component\compound</Filter>
</ClInclude>
<ClInclude Include="..\src\pc\djui\djui_panel_main.h">
<Filter>Source Files\src\pc\djui\panel</Filter>
</ClInclude>
<ClInclude Include="..\src\pc\utils\misc.h">
<Filter>Source Files\src\pc\utils</Filter>
</ClInclude>
<ClInclude Include="..\src\pc\djui\djui_font.h">
<Filter>Source Files\src\pc\djui</Filter>
</ClInclude>
<ClInclude Include="..\src\pc\djui\djui_panel_debug.h">
<Filter>Source Files\src\pc\djui\panel</Filter>
</ClInclude>
<ClInclude Include="..\src\pc\djui\djui_panel_options.h">
<Filter>Source Files\src\pc\djui\panel</Filter>
</ClInclude>
<ClInclude Include="..\src\pc\djui\djui_cursor.h">
<Filter>Source Files\src\pc\djui\component</Filter>
</ClInclude>
<ClInclude Include="..\src\pc\djui\djui_three_panel.h">
<Filter>Source Files\src\pc\djui\component</Filter>
</ClInclude>
<ClInclude Include="..\src\pc\djui\djui_panel_sound.h">
<Filter>Source Files\src\pc\djui\panel</Filter>
</ClInclude>
<ClInclude Include="..\src\pc\djui\djui_panel.h">
<Filter>Source Files\src\pc\djui\panel</Filter>
</ClInclude>
<ClInclude Include="..\src\pc\djui\djui_slider.h">
<Filter>Source Files\src\pc\djui\component\compound</Filter>
</ClInclude>
<ClInclude Include="..\src\pc\djui\djui_panel_camera.h">
<Filter>Source Files\src\pc\djui\panel</Filter>
</ClInclude>
<ClInclude Include="..\src\pc\djui\djui_checkbox.h">
<Filter>Source Files\src\pc\djui\component\compound</Filter>
</ClInclude>
<ClInclude Include="..\src\pc\djui\djui_panel_display.h">
<Filter>Source Files\src\pc\djui\panel</Filter>
</ClInclude>
<ClInclude Include="..\src\pc\djui\djui_selectionbox.h">
<Filter>Source Files\src\pc\djui\component\compound</Filter>
</ClInclude>
<ClInclude Include="..\src\pc\djui\djui_panel_controls.h">
<Filter>Source Files\src\pc\djui\panel</Filter>
</ClInclude>
<ClInclude Include="..\src\pc\djui\djui_bind.h">
<Filter>Source Files\src\pc\djui\component\compound</Filter>
</ClInclude>
<ClInclude Include="..\src\pc\djui\djui_panel_host.h">
<Filter>Source Files\src\pc\djui\panel</Filter>
</ClInclude>
<ClInclude Include="..\src\pc\djui\djui_panel_menu.h">
<Filter>Source Files\src\pc\djui\panel</Filter>
</ClInclude>
<ClInclude Include="..\src\pc\djui\djui_panel_host_message.h">
<Filter>Source Files\src\pc\djui\panel</Filter>
</ClInclude>
<ClInclude Include="..\src\pc\djui\djui_inputbox.h">
<Filter>Source Files\src\pc\djui\component\compound</Filter>
</ClInclude>
<ClInclude Include="..\src\pc\djui\djui_panel_join.h">
<Filter>Source Files\src\pc\djui\panel</Filter>
</ClInclude>
<ClInclude Include="..\src\pc\djui\djui_panel_join_message.h">
<Filter>Source Files\src\pc\djui\panel</Filter>
</ClInclude>
<ClInclude Include="..\src\pc\utils\string_builder.h">
<Filter>Source Files\src\pc\utils</Filter>
</ClInclude>
<ClInclude Include="..\src\pc\djui\djui_popup.h">
<Filter>Source Files\src\pc\djui\component\compound</Filter>
</ClInclude>
<ClInclude Include="..\src\pc\djui\djui_panel_host_save.h">
<Filter>Source Files\src\pc\djui\panel</Filter>
</ClInclude>
<ClInclude Include="..\src\pc\djui\djui_panel_confirm.h">
<Filter>Source Files\src\pc\djui\panel</Filter>
</ClInclude>
<ClInclude Include="..\src\pc\djui\djui_panel_pause.h">
<Filter>Source Files\src\pc\djui\panel</Filter>
</ClInclude>
<ClInclude Include="..\src\pc\djui\djui_panel_cheats.h">
<Filter>Source Files\src\pc\djui\panel</Filter>
</ClInclude>
<ClInclude Include="..\src\pc\djui\djui_chat_box.h">
<Filter>Source Files\src\pc\djui\component</Filter>
</ClInclude>
<ClInclude Include="..\src\pc\djui\djui_chat_message.h">
<Filter>Source Files\src\pc\djui\component\compound</Filter>
</ClInclude>
</ItemGroup>
</Project>

View file

@ -1,2 +1,5 @@
#!/bin/bash
make BETTERCAMERA=1 NODRAWINGDISTANCE=1 DEBUG=1 IMMEDIATELOAD=1 DEVELOPMENT=1 STRICT=1 && winpty cgdb ./build/us_pc/sm64.us.f3dex2e.exe -ex 'break debug_breakpoint_here' -ex 'run' -ex 'quit'
#make BETTERCAMERA=1 NODRAWINGDISTANCE=1 DEBUG=1 IMMEDIATELOAD=1 DEVELOPMENT=1 STRICT=1 && winpty cgdb ./build/us_pc/sm64.us.f3dex2e.exe -ex 'break debug_breakpoint_here' -ex 'run' -ex 'quit'
#make BETTERCAMERA=1 NODRAWINGDISTANCE=1 DEBUG=1 IMMEDIATELOAD=1 DEVELOPMENT=1 STRICT=1 && winpty cgdb ./build/us_pc/sm64.us.f3dex2e.exe -ex 'break debug_breakpoint_here' -ex 'run --server 27015 --configfile sm64config_server.txt' -ex 'quit'
#make BETTERCAMERA=1 NODRAWINGDISTANCE=1 DEBUG=1 IMMEDIATELOAD=1 DEVELOPMENT=1 STRICT=1 && ./build/us_pc/sm64.us.f3dex2e.exe --server 27015 --configfile sm64config_server.txt
make BETTERCAMERA=1 NODRAWINGDISTANCE=1 DEBUG=1 IMMEDIATELOAD=1 DEVELOPMENT=1 STRICT=1 && ./build/us_pc/sm64.us.f3dex2e.exe

View file

@ -1,2 +1,3 @@
#!/bin/bash
winpty cgdb ./build/us_pc/sm64.us.f3dex2e.exe -ex 'break debug_breakpoint_here'
make BETTERCAMERA=1 NODRAWINGDISTANCE=1 DEBUG=1 IMMEDIATELOAD=1 DEVELOPMENT=1 STRICT=1 && winpty cgdb ./build/us_pc/sm64.us.f3dex2e.exe -ex 'break debug_breakpoint_here'
#make BETTERCAMERA=1 NODRAWINGDISTANCE=1 DEBUG=1 IMMEDIATELOAD=1 DEVELOPMENT=1 STRICT=1 && winpty cgdb ./build/us_pc/sm64.us.f3dex2e.exe -ex 'break debug_breakpoint_here' -ex 'run --server 27015 --configfile sm64config_server.txt'

18
developer/flags.sh Normal file
View file

@ -0,0 +1,18 @@
#!/bin/bash
set -e
function compiler() {
make clean
make RENDER_API=$1 WINDOW_API=$2 AUDIO_API=$3 CONTROLLER_API=$4
mv ./build/us_pc/sm64.us.f3dex2e.exe ./build/us_pc/$5.exe
}
compiler GL_LEGACY SDL1 SDL1 SDL1 legacy_1
compiler GL SDL1 SDL1 SDL1 gl_1
compiler D3D11 DXGI SDL1 SDL1 d3d11_1
compiler D3D12 DXGI SDL1 SDL1 d3d12_1
compiler GL_LEGACY SDL2 SDL2 SDL2 legacy_2
compiler GL SDL1 SDL2 SDL2 gl_2
compiler D3D11 DXGI SDL2 SDL2 d3d11_2
compiler D3D12 DXGI SDL2 SDL2 d3d12_2

View file

@ -21,6 +21,7 @@
#define _GBI_H_
#include <PR/ultratypes.h>
#include "src/pc/djui/djui_gbi.h"
/*
* To use the F3DEX ucodes, define F3DEX_GBI before include this file.

View file

@ -1,156 +0,0 @@
#ifndef TEXT_OPTIONS_STRINGS_H
#define TEXT_OPTIONS_STRINGS_H
/* Extended options menu text */
// Menu title strings
#define TEXT_OPT_OPTIONS _("OPTIONS")
#define TEXT_OPT_CAMERA _("CAMERA")
#define TEXT_OPT_CONTROLS _("CONTROLS")
#define TEXT_OPT_VIDEO _("DISPLAY")
#define TEXT_OPT_AUDIO _("SOUND")
#define TEXT_OPT_CHEATS _("CHEATS")
// Markers
#define TEXT_OPT_HIGHLIGHT _("O")
#define TEXT_OPT_UNBOUND _("NONE")
// Language specific strings
#if defined(VERSION_JP) || defined(VERSION_SH)
// TODO: Actually translate this to JP
// No . in JP
#define TEXT_OPT_PRESSKEY _("・・・")
// Option strings
#define TEXT_OPT_BUTTON1 _(" OPTIONS")
#define TEXT_OPT_BUTTON2 _(" RETURN")
#define TEXT_OPT_ENABLED _("ENABLED")
#define TEXT_OPT_DISABLED _("DISABLED")
#define TEXT_OPT_CAMX _("CAMERA X SENSITIVITY")
#define TEXT_OPT_CAMY _("CAMERA Y SENSITIVITY")
#define TEXT_OPT_INVERTX _("INVERT X AXIS")
#define TEXT_OPT_INVERTY _("INVERT Y AXIS")
#define TEXT_OPT_CAMC _("CAMERA CENTRE AGGRESSION")
#define TEXT_OPT_CAMP _("CAMERA PAN LEVEL")
#define TEXT_OPT_CAMD _("CAMERA DECELERATION")
#define TEXT_OPT_CAMON _("FREE CAMERA")
#define TEXT_OPT_ANALOGUE _("ANALOGUE CAMERA")
#define TEXT_OPT_MOUSE _("MOUSE LOOK")
#define TEXT_OPT_TEXFILTER _("TEXTURE FILTERING")
#define TEXT_OPT_FSCREEN _("FULLSCREEN")
#define TEXT_OPT_NEAREST _("NEAREST")
#define TEXT_OPT_LINEAR _("LINEAR")
#define TEXT_OPT_MVOLUME _("MASTER VOLUME")
#define TEXT_OPT_MUSVOLUME _("MUSIC VOLUME")
#define TEXT_OPT_SFXVOLUME _("SFX VOLUME")
#define TEXT_OPT_ENVVOLUME _("ENV VOLUME")
#define TEXT_OPT_VSYNC _("VERTICAL SYNC")
#define TEXT_OPT_AUTO _("AUTO")
#define TEXT_OPT_HUD _("HUD")
#define TEXT_OPT_THREEPT _("THREE POINT")
#define TEXT_OPT_APPLY _("APPLY")
#define TEXT_OPT_RESETWND _("RESET WINDOW")
#define TEXT_BIND_A _("A BUTTON")
#define TEXT_BIND_B _("B BUTTON")
#define TEXT_BIND_START _("START BUTTON")
#define TEXT_BIND_L _("L TRIGGER")
#define TEXT_BIND_R _("R TRIGGER")
#define TEXT_BIND_Z _("Z TRIGGER")
#define TEXT_BIND_C_UP _("C-UP")
#define TEXT_BIND_C_DOWN _("C-DOWN")
#define TEXT_BIND_C_LEFT _("C-LEFT")
#define TEXT_BIND_C_RIGHT _("C-RIGHT")
#define TEXT_BIND_UP _("STICK UP")
#define TEXT_BIND_DOWN _("STICK DOWN")
#define TEXT_BIND_LEFT _("STICK LEFT")
#define TEXT_BIND_RIGHT _("STICK RIGHT")
#define TEXT_OPT_DEADZONE _("STICK DEADZONE")
#define TEXT_OPT_RUMBLE _("RUMBLE STRENGTH")
#define TEXT_OPT_CHEAT1 _("ENABLE CHEATS")
#define TEXT_OPT_CHEAT2 _("MOONJUMP (PRESS L)")
#define TEXT_OPT_CHEAT3 _("INVINCIBLE MARIO")
#define TEXT_OPT_CHEAT4 _("INFINITE LIVES")
#define TEXT_OPT_CHEAT5 _("SUPER SPEED")
#define TEXT_OPT_CHEAT6 _("SUPER RESPONSIVE CONTROLS")
#define TEXT_OPT_CHEAT7 _("EXIT COURSE AT ANY TIME")
#define TEXT_OPT_CHEAT8 _("HUGE MARIO")
#define TEXT_OPT_CHEAT9 _("TINY MARIO")
#else // VERSION
// Markers
#define TEXT_OPT_PRESSKEY _("...")
// Option strings
#define TEXT_OPT_BUTTON1 _("[R] Options")
#define TEXT_OPT_BUTTON2 _("[R] Return")
#define TEXT_OPT_ENABLED _("Enabled")
#define TEXT_OPT_DISABLED _("Disabled")
#define TEXT_OPT_CAMX _("Camera X Sensitivity")
#define TEXT_OPT_CAMY _("Camera Y Sensitivity")
#define TEXT_OPT_INVERTX _("Invert X Axis")
#define TEXT_OPT_INVERTY _("Invert Y Axis")
#define TEXT_OPT_CAMC _("Camera Centre Aggression")
#define TEXT_OPT_CAMP _("Camera Pan Level")
#define TEXT_OPT_CAMD _("Camera Deceleration")
#define TEXT_OPT_CAMON _("Free Camera")
#define TEXT_OPT_ANALOGUE _("Analogue Camera")
#define TEXT_OPT_MOUSE _("Mouse Look")
#define TEXT_OPT_TEXFILTER _("Texture Filtering")
#define TEXT_OPT_FSCREEN _("Fullscreen")
#define TEXT_OPT_NEAREST _("Nearest")
#define TEXT_OPT_LINEAR _("Linear")
#define TEXT_OPT_MVOLUME _("Master Volume")
#define TEXT_OPT_MUSVOLUME _("Music Volume")
#define TEXT_OPT_SFXVOLUME _("Sfx Volume")
#define TEXT_OPT_ENVVOLUME _("Env Volume")
#define TEXT_OPT_VSYNC _("Vertical Sync")
#define TEXT_OPT_AUTO _("Auto")
#define TEXT_OPT_HUD _("HUD")
#define TEXT_OPT_THREEPT _("Three-point")
#define TEXT_OPT_APPLY _("Apply")
#define TEXT_OPT_RESETWND _("Reset Window")
#define TEXT_BIND_A _("A Button")
#define TEXT_BIND_B _("B Button")
#define TEXT_BIND_START _("Start Button")
#define TEXT_BIND_L _("L Trigger")
#define TEXT_BIND_R _("R Trigger")
#define TEXT_BIND_Z _("Z Trigger")
#define TEXT_BIND_C_UP _("C-Up")
#define TEXT_BIND_C_DOWN _("C-Down")
#define TEXT_BIND_C_LEFT _("C-Left")
#define TEXT_BIND_C_RIGHT _("C-Right")
#define TEXT_BIND_UP _("Stick Up")
#define TEXT_BIND_DOWN _("Stick Down")
#define TEXT_BIND_LEFT _("Stick Left")
#define TEXT_BIND_RIGHT _("Stick Right")
#define TEXT_OPT_DEADZONE _("Stick Deadzone")
#define TEXT_OPT_RUMBLE _("Rumble Strength")
#define TEXT_OPT_CHEAT1 _("Enable cheats")
#define TEXT_OPT_CHEAT2 _("Moonjump (Press L)")
#define TEXT_OPT_CHEAT3 _("Invincible Mario")
#define TEXT_OPT_CHEAT4 _("Infinite lives")
#define TEXT_OPT_CHEAT5 _("Super speed")
#define TEXT_OPT_CHEAT6 _("Super responsive controls")
#define TEXT_OPT_CHEAT7 _("Exit course at any time")
#define TEXT_OPT_CHEAT8 _("Huge Mario")
#define TEXT_OPT_CHEAT9 _("Tiny Mario")
#define TEXT_OPT_LUIGISND _("Luigi Sounds")
#endif // VERSION
#endif // TEXT_OPTIONS_STRINGS_H

View file

@ -3,10 +3,6 @@
#include "text_menu_strings.h"
#ifdef EXT_OPTIONS_MENU
#include "text_options_strings.h"
#endif
/**
* Global Symbols
*/

View file

@ -5,6 +5,7 @@
#ifdef IMMEDIATELOAD
#include "levels/menu/header.h"
#include "levels/scripts.h"
#else
#include "levels/intro/header.h"
#endif
@ -12,15 +13,14 @@
#include "make_const_nonconst.h"
const LevelScript level_script_entry[] = {
INIT_LEVEL(),
SLEEP(/*frames*/ 2),
BLACKOUT(/*active*/ FALSE),
SET_REG(/*value*/ 0),
#ifdef IMMEDIATELOAD
EXECUTE(/*seg*/ 0x14, /*script*/ _introSegmentRomStart, /*scriptEnd*/ _introSegmentRomEnd, /*entry*/ level_main_menu_entry_1),
JUMP(/*target*/ level_main_menu_entry_1),
#else
EXECUTE(/*seg*/ 0x14, /*script*/ _introSegmentRomStart, /*scriptEnd*/ _introSegmentRomEnd, /*entry*/ level_intro_entry_1),
JUMP(/*target*/ level_script_entry),
#endif
SET_REG(/*value*/ LEVEL_CASTLE_GROUNDS),
JUMP(/*target*/ level_main_scripts_entry),
// old behavior (intro)
//INIT_LEVEL(),
//SLEEP(/*frames*/ 2),
//BLACKOUT(/*active*/ FALSE),
//SET_REG(/*value*/ 0),
//EXECUTE(/*seg*/ 0x14, /*script*/ _introSegmentRomStart, /*scriptEnd*/ _introSegmentRomEnd, /*entry*/ level_intro_entry_1),
//JUMP(/*target*/ level_script_entry),
};

203
misc/n64-controller.svg Normal file
View file

@ -0,0 +1,203 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="210mm"
height="297mm"
viewBox="0 0 210 297"
version="1.1"
id="svg3123"
inkscape:version="1.0.1 (3bc2e813f5, 2020-09-07)"
sodipodi:docname="n64-controller.svg">
<defs
id="defs3117">
<pattern
id="EMFhbasepattern"
patternUnits="userSpaceOnUse"
width="6"
height="6"
x="0"
y="0" />
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="0.98422794"
inkscape:cx="366.87429"
inkscape:cy="482.24232"
inkscape:document-units="mm"
inkscape:current-layer="layer1"
inkscape:document-rotation="0"
showgrid="false"
inkscape:window-width="2560"
inkscape:window-height="1387"
inkscape:window-x="1272"
inkscape:window-y="-8"
inkscape:window-maximized="1" />
<metadata
id="metadata3120">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1">
<path
style="opacity:1;fill:#999999;stroke:#000000;stroke-width:2;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 159.02164,179.47574 c 4.22025,-1.90449 6.28702,-7.08236 7.60023,-19.04089 1.49599,-13.62284 0.24084,-34.30392 -1.99705,-47.32577 -0.20446,-1.18966 -0.20446,-1.18966 -0.81578,1.12198 -2.98495,11.28726 -13.59592,24.03716 -29.26288,26.03289 -0.81252,0.1035 -3.77405,0.3089 -3.60094,0.36847 0.53476,0.18404 2.20561,0.19552 2.97591,0.42882 2.64606,0.8014 6.14267,5.68736 7.86503,13.7161 4.7533,22.15739 9.09126,28.37366 17.23548,24.6984 z"
id="path3879"
sodipodi:nodetypes="sssssssss" />
<path
style="opacity:1;fill:#999999;stroke:#000000;stroke-width:2;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 32.861846,179.99085 c 5.00628,-1.30397 7.90516,-7.49824 11.63722,-24.86622 1.74689,-8.12955 4.040457,-12.01723 6.760691,-13.41247 1.175878,-0.60312 7.936069,-0.81879 7.254723,-1.00324 -0.347508,-0.0941 -7.714416,-0.40085 -8.622923,-0.51096 -13.947408,-1.69042 -24.46162,-12.73569 -27.45118,-23.32573 -0.3377,-1.19622 -0.67694,-2.2379 -0.75388,-2.31484 -0.0769,-0.0769 -0.4002,1.61825 -0.71836,3.76707 -2.15481,14.55314 -2.561091,37.51868 -0.08673,49.90929 1.46209,7.32157 4.05435,11.05512 8.25242,11.88568 1.64494,0.32544 2.03682,0.31192 3.728019,-0.12858 z"
id="path3877"
sodipodi:nodetypes="ssssssscsss" />
<path
style="opacity:1;fill:#666666;stroke:#000000;stroke-width:2;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 34.669026,91.826028 27.72169,-6.884126 1.818325,-6.455174 c 0,0 -24.936365,1.49832 -32.278785,8.638042 l 0.172599,5.12895 z"
id="path3885"
sodipodi:nodetypes="cccccc" />
<path
style="opacity:1;fill:#666666;stroke:#000000;stroke-width:2;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 151.88386,91.82585 -27.72169,-6.884125 -1.81832,-6.455175 c 0,0 24.93636,1.49832 32.27878,8.638043 l -0.1726,5.128949 z"
id="path3885-3"
sodipodi:nodetypes="cccccc" />
<path
style="opacity:1;fill:#b3b3b3;stroke:#000000;stroke-width:2;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 96.641306,210.13404 c 3.380854,-1.51705 6.454544,-6.19977 9.099164,-13.8624 2.68812,-7.78869 3.74969,-12.87923 6.70151,-32.13562 3.19508,-20.84329 4.75644,-22.60184 20.76255,-23.38477 21.1825,-1.03614 31.92894,-10.58468 31.38845,-27.88957 -0.43636,-13.97068 -8.39177,-24.158157 -21.67654,-27.75838 -3.41038,-0.924226 -14.1984,-2.461285 -17.10739,-2.719429 0,0 -2.8761,-5.127414 -4.06555,-6.958522 -0.83939,-1.771386 -15.39779,-6.171957 -28.038814,-6.171957 -11.83651,0 -27.511412,3.714691 -28.56411,6.145662 l -3.466375,6.79723 -7.516145,1.067272 c -19.91914,2.168581 -30.28071,10.635003 -32.25997,26.359574 -2.35782,18.73214 9.00373,30.06503 31.20249,31.12376 15.92894,0.7597 17.70816,2.72014 20.74733,22.86039 2.41524,16.0055 3.44807,21.53411 5.14373,27.53369 4.49992,15.9216 10.38385,22.25339 17.64967,18.99307 z"
id="path3819"
sodipodi:nodetypes="ssssssccscccsssss" />
<ellipse
style="opacity:1;fill:#666666;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="path4050"
cx="93.281662"
cy="149.23048"
rx="15.356243"
ry="15.389847" />
<path
style="opacity:1;fill:#1a1a1a;stroke:#000000;stroke-width:0.5;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 97.472306,157.25386 c 2.869884,-1.16156 2.592834,-0.84172 4.226594,-4.87944 1.31925,-3.26043 1.31925,-3.26043 -0.004,-6.51708 -1.62318,-3.99318 -1.25715,-3.62328 -5.222619,-5.27796 -3.293655,-1.37436 -3.293655,-1.37436 -6.766293,0.0702 -3.472637,1.44446 -3.472637,1.44446 -4.955151,4.95638 -1.482514,3.51191 -1.482514,3.51191 0,7.02456 1.482514,3.51266 1.482514,3.51266 4.934707,4.95635 3.352146,1.40187 3.480201,1.43206 4.418804,1.04148 0.531635,-0.22124 2.047475,-0.83971 3.368526,-1.37439 z"
id="path3827" />
<path
style="fill:#e6e6e6;stroke-width:0.5;opacity:1;stroke:#000000;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none"
d="m 90.808556,156.06467 c -3.19709,-0.95777 -5.44345,-4.93001 -4.69055,-8.29433 1.46124,-6.52952 10.04671,-7.88776 13.29527,-2.10334 3.226694,5.74546 -2.20892,12.31367 -8.60472,10.39767 z"
id="path3829" />
<path
style="opacity:1;fill:#cccccc;stroke:#000000;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 65.017829,75.401478 -3.343628,6.794806 c 0,0 6.248151,22.468596 5.826195,20.433286 -0.827522,-9.076031 -2.462914,-28.250425 -2.482567,-27.228092 z"
id="path3881"
sodipodi:nodetypes="cccc" />
<path
style="fill:#000000;stroke-width:0.264369"
id="path3138"
d="" />
<circle
style="opacity:1;fill:#ff0000;stroke:#000000;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="path3892"
cx="93.14756"
cy="119.22792"
r="6.7085466" />
<path
id="rect3924"
style="opacity:1;fill:none;stroke:#000000;stroke-width:0.5;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 123.98074,122.64871 1.54028,-1.51666 3.96468,3.71008 -1.77651,1.15706 z"
sodipodi:nodetypes="ccccc" />
<circle
style="opacity:1;fill:#00ff00;stroke:#000000;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="path3892-0"
cx="121.27341"
cy="118.1497"
r="5.2315807" />
<circle
style="opacity:1;fill:#0000ff;stroke:#000000;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="path3892-0-9"
cx="131.88081"
cy="129.24153"
r="5.2315807" />
<rect
style="opacity:0.645161;fill:#999999;stroke:#000000;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect3948"
width="29.365215"
height="6.4055333"
x="78.46347"
y="84.188957"
ry="3.1025405"
rx="3.1738269" />
<path
style="opacity:1;fill:#666666;stroke:#000000;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 121.7435,75.425349 3.34362,6.794806 c 0,0 -6.24815,22.468595 -5.82619,20.433285 0.82752,-9.07603 2.46291,-28.250424 2.48257,-27.228091 z"
id="path3881-7"
sodipodi:nodetypes="cccc" />
<ellipse
style="opacity:1;fill:#999999;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;fill-opacity:1"
id="path3982"
cx="46.353729"
cy="114.51382"
rx="16.790049"
ry="16.844238" />
<path
id="rect3984"
style="opacity:1;fill:#333333;fill-opacity:1;stroke:#000000;stroke-width:3.77953;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="M 174.89453 390.91992 C 168.15317 390.91992 162.72656 393.73545 162.72656 397.23242 L 162.72656 419.83789 L 140.12109 419.83789 C 136.62412 419.83789 133.80859 425.26451 133.80859 432.00586 L 133.80859 432.81445 C 133.80859 439.55581 136.62412 444.98242 140.12109 444.98242 L 162.72656 444.98242 L 162.72656 467.58789 C 162.72656 471.08486 168.15317 473.90039 174.89453 473.90039 L 175.70312 473.90039 C 182.44449 473.90039 187.87109 471.08486 187.87109 467.58789 L 187.87109 444.98242 L 210.47656 444.98242 C 213.97353 444.98242 216.78906 439.55581 216.78906 432.81445 L 216.78906 432.00586 C 216.78906 425.26451 213.97353 419.83789 210.47656 419.83789 L 187.87109 419.83789 L 187.87109 397.23242 C 187.87109 393.73545 182.44449 390.91992 175.70312 390.91992 L 174.89453 390.91992 z "
transform="scale(0.26458333)" />
<circle
style="opacity:1;fill:#999999;fill-opacity:1;stroke:#000000;stroke-width:0.5;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="path4048"
cy="109.39449"
cx="143.2998"
r="11.098639" />
<circle
style="opacity:1;fill:#ffff00;stroke:#000000;stroke-width:0.82998;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="path3892-0-5"
cx="134.47882"
cy="108.94062"
r="4.3421068" />
<circle
style="opacity:1;fill:#ffff00;stroke:#000000;stroke-width:0.829979;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="path3892-0-5-2"
cx="152.28836"
cy="108.94061"
r="4.3421068" />
<circle
style="opacity:1;fill:#ffff00;stroke:#000000;stroke-width:0.829979;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="path3892-0-5-5"
cx="142.94675"
cy="100.47269"
r="4.3421068" />
<circle
style="opacity:1;fill:#ffff00;stroke:#000000;stroke-width:0.829979;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="path3892-0-5-7"
cx="143.04756"
cy="118.31582"
r="4.3421068" />
<path
style="opacity:1;fill:#e6e6e6;stroke:#ffffff;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 91.310516,154.60644 c -2.517257,-0.75411 -4.28595,-3.88169 -3.693146,-6.53061 1.15052,-5.14108 7.910368,-6.2105 10.468147,-1.65608 2.540573,4.52373 -1.739209,9.69528 -6.775001,8.18669 z"
id="path3829-4" />
<path
style="opacity:1;fill:#e6e6e6;stroke:#ffffff;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 91.933837,152.79309 c -1.6719,-0.50086 -2.846622,-2.57812 -2.452896,-4.33746 0.764147,-3.41458 5.253869,-4.12486 6.952682,-1.09993 1.687385,3.00455 -1.15514,6.43936 -4.499786,5.43739 z"
id="path3829-4-2" />
<path
style="opacity:1;fill:#e6e6e6;stroke:#ffffff;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 92.606431,150.83354 c -0.758421,-0.2272 -1.291308,-1.1695 -1.112703,-1.96759 0.346639,-1.54895 2.383302,-1.87115 3.153935,-0.49896 0.765443,1.36295 -0.524004,2.92108 -2.041232,2.46655 z"
id="path3829-4-2-1" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 12 KiB

View file

@ -115,5 +115,5 @@ struct Character gCharacters[CT_MAX] = {
struct Character* get_character_sound(struct MarioState* m) {
if (m == NULL || m->character == NULL) { return &gCharacters[CT_MARIO]; }
return configLuigiSounds ? m->character : &gCharacters[CT_MARIO];
return m->character;
}

View file

@ -1,166 +0,0 @@
#include <stdio.h>
#include <ultra64.h>
#include <string.h>
#include "chat.h"
#include "game_init.h"
#include "ingame_menu.h"
#include "mario_misc.h"
#include "segment2.h"
#include "gfx_dimensions.h"
#include "config.h"
#include "PR/gbi.h"
#include "pc/controller/controller_keyboard.h"
#include "pc/network/network.h"
#include "audio_defines.h"
#include "audio/external.h"
#include "menu/file_select.h"
#define CHAT_DIALOG_MAX 96
#define CHAT_MESSAGES_MAX 16
#define CHAT_LIFE_MAX 400
struct ChatMessage {
u8 dialog[CHAT_DIALOG_MAX];
enum ChatMessageType type;
u16 life;
u8 color[3];
};
static char inputMessage[CHAT_DIALOG_MAX] = { 0 };
static struct ChatMessage message[CHAT_MESSAGES_MAX] = { 0 };
static u8 onMessageIndex = 0;
static u8 sInChatInput = FALSE;
#define CHAT_SCALE 0.5f
#define CHAT_SPACE 10.0f
#define CHATBOX_PAD_X 0.0215f
#define CHATBOX_SCALE_X 0.00385f
#define CHATBOX_SCALE_Y 0.115f
#define CHATBOX_X 2.0f
#define CHATBOX_Y 11.0f
#define CHAT_X 4.0f
#define CHAT_Y -18.0f
static void render_chat_message(struct ChatMessage* chatMessage, u8 index) {
f32 textWidth = get_generic_dialog_width(chatMessage->dialog);
f32 alphaScale = ((f32)chatMessage->life / (f32)(CHAT_LIFE_MAX / 20.0f));
alphaScale *= alphaScale;
if (alphaScale > 1) { alphaScale = 1; }
f32 chatBoxWidth = CHATBOX_SCALE_X * textWidth + CHATBOX_PAD_X;
create_dl_translation_matrix(MENU_MTX_PUSH, GFX_DIMENSIONS_FROM_LEFT_EDGE(CHATBOX_X), CHATBOX_Y + index * CHAT_SPACE, 0);
create_dl_scale_matrix(MENU_MTX_NOPUSH, chatBoxWidth, CHATBOX_SCALE_Y, 1.0f);
u8 boxR, boxG, boxB;
if (chatMessage->type == CMT_INPUT) {
boxR = 150;
boxG = 150;
boxB = 255;
} else {
f32 rgbScale = (((f32)chatMessage->life - ((f32)CHAT_LIFE_MAX * 0.98f)) / ((f32)CHAT_LIFE_MAX * 0.02f));
if (chatMessage->type == CMT_LOCAL || rgbScale < 0) { rgbScale = 0; }
boxR = 255 * rgbScale;
boxG = 255 * rgbScale;
boxB = 255 * rgbScale;
}
gDPSetEnvColor(gDisplayListHead++, boxR, boxG, boxB, 110 * alphaScale);
gSPDisplayList(gDisplayListHead++, dl_draw_text_bg_box);
create_dl_scale_matrix(MENU_MTX_NOPUSH, CHAT_SCALE / chatBoxWidth, CHAT_SCALE / CHATBOX_SCALE_Y, 1.0f);
u8 textR, textG, textB;
switch (chatMessage->type) {
case CMT_LOCAL: textR = 200; textG = 200; textB = 255; break;
case CMT_INPUT: textR = 0; textG = 0; textB = 0; break;
case CMT_SYSTEM: textR = 255; textG = 255; textB = 190; break;
default: textR = 255; textG = 255; textB = 255; break;
}
gSPDisplayList(gDisplayListHead++, dl_ia_text_begin);
gDPSetEnvColor(gDisplayListHead++, textR, textG, textB, 255 * alphaScale);
print_generic_string(CHAT_X, CHAT_Y, chatMessage->dialog);
if (chatMessage->type == CMT_REMOTE || chatMessage->type == CMT_SYSTEM) {
// if it's someone else's message, highlight the icon with their color
u8 starR = chatMessage->color[0];
u8 starG = chatMessage->color[1];
u8 starB = chatMessage->color[2];
gDPSetEnvColor(gDisplayListHead++, starR, starG, starB, 255 * alphaScale);
create_dl_translation_matrix(MENU_MTX_PUSH, CHAT_X, CHAT_Y, 0.0f);
render_generic_char(chatMessage->dialog[0]);
gSPPopMatrix(gDisplayListHead++, G_MTX_MODELVIEW);
}
gSPDisplayList(gDisplayListHead++, dl_ia_text_end);
gSPPopMatrix(gDisplayListHead++, G_MTX_MODELVIEW);
}
void chat_add_message_ext(char* ascii, enum ChatMessageType chatMessageType, const u8 color[3]) {
u8 character = '?';
switch (chatMessageType) {
case CMT_INPUT:
case CMT_LOCAL: character = 0xFD; break;
case CMT_REMOTE: character = 0xFA; break;
case CMT_SYSTEM: character = 0xF9; break;
}
struct ChatMessage* msg = &message[onMessageIndex];
msg->dialog[0] = character;
msg->dialog[1] = 0x9E;
str_ascii_to_dialog(ascii, &msg->dialog[2], MIN(strlen(ascii), CHAT_DIALOG_MAX - 3));
msg->life = (sSelectedFileNum != 0) ? CHAT_LIFE_MAX : CHAT_LIFE_MAX / 3;
msg->type = chatMessageType;
msg->color[0] = color[0];
msg->color[1] = color[1];
msg->color[2] = color[2];
onMessageIndex = (onMessageIndex + 1) % CHAT_MESSAGES_MAX;
play_sound((msg->type == CMT_LOCAL) ? SOUND_MENU_MESSAGE_DISAPPEAR : SOUND_MENU_MESSAGE_APPEAR, gDefaultSoundArgs);
}
void chat_add_message(char* ascii, enum ChatMessageType chatMessageType) {
const u8 defaultColor[3] = { 255, 255, 255 };
chat_add_message_ext(ascii, chatMessageType, defaultColor);
}
static void chat_stop_input(void) {
sInChatInput = FALSE;
keyboard_stop_text_input();
}
static void chat_send_input(void) {
sInChatInput = FALSE;
keyboard_stop_text_input();
if (strlen(gTextInput) == 0) { return; }
chat_add_message(gTextInput, CMT_LOCAL);
// our message has the same color as our shirt
network_send_chat(gTextInput, get_player_color(gNetworkPlayerLocal->globalIndex, 0));
}
void chat_start_input(void) {
sInChatInput = TRUE;
keyboard_start_text_input(TIM_SINGLE_LINE, CHAT_DIALOG_MAX - 3, chat_stop_input, chat_send_input);
}
void render_chat(void) {
u8 count = 0;
if (sInChatInput) {
struct ChatMessage inputMessage = { 0 };
inputMessage.type = CMT_INPUT;
inputMessage.dialog[0] = 0xFD;
inputMessage.dialog[1] = 0x9E;
str_ascii_to_dialog(gTextInput, &inputMessage.dialog[2], MIN(strlen(gTextInput), CHAT_DIALOG_MAX - 3));
inputMessage.life = CHAT_LIFE_MAX;
render_chat_message(&inputMessage, count++);
}
u8 index = onMessageIndex;
for (int i = 0; i < CHAT_MESSAGES_MAX; i++) {
if (--index >= CHAT_MESSAGES_MAX) { index = CHAT_MESSAGES_MAX - 1; }
if (message[index].life == 0) { continue; }
render_chat_message(&message[index], count++);
message[index].life--;
}
}

View file

@ -1,16 +0,0 @@
#ifndef CHAT_H
#define CHAT_H
enum ChatMessageType {
CMT_LOCAL,
CMT_REMOTE,
CMT_SYSTEM,
CMT_INPUT,
};
void render_chat(void);
void chat_add_message(char* ascii, enum ChatMessageType chatMessageType);
void chat_add_message_ext(char* ascii, enum ChatMessageType chatMessageType, const u8 color[3]);
void chat_start_input(void);
#endif

View file

@ -21,6 +21,7 @@
#include "segment_symbols.h"
#include "thread6.h"
#include "rng_position.h"
#include "src/pc/djui/djui.h"
#include <prevent_bss_reordering.h>
#ifdef BETTERCAMERA
#include "bettercamera.h"
@ -259,6 +260,9 @@ void end_master_display_list(void) {
draw_profiler();
}
extern void djui_render(void);
djui_render();
gDPFullSync(gDisplayListHead++);
gSPEndDisplayList(gDisplayListHead++);
@ -460,7 +464,7 @@ void read_controller_inputs(void) {
// controller information.
if (gControllerBits) {
osRecvMesg(&gSIEventMesgQueue, &D_80339BEC, OS_MESG_BLOCK);
osContGetReadData(&gControllerPads[0]);
osContGetReadData(gInteractableOverridePad ? &gInteractablePad : &gControllerPads[0]);
}
run_demo_inputs();

View file

@ -26,13 +26,10 @@
#include "macros.h"
#include "pc/cheats.h"
#include "pc/network/network.h"
#include "pc/djui/djui.h"
#ifdef BETTERCAMERA
#include "bettercamera.h"
#endif
#ifdef EXT_OPTIONS_MENU
#include "options_menu.h"
#endif
#include "chat.h"
u16 gDialogColorFadeTimer;
s8 gLastDialogLineNum;
@ -414,26 +411,31 @@ void render_multi_text_string(s16 *xPos, s16 *yPos, s8 multiTextID)
}
#endif
u8 str_ascii_char_to_dialog(char c) {
switch (c) {
case '\'': return 0x3E;
case '.': return 0x3F;
case ',': return DIALOG_CHAR_COMMA;
case '-': return 0x9F;
case '(': return 0xE1;
case ')': return 0xE3;
case '&': return 0xE5;
case '!': return 0xF2;
case '%': return 0xF3;
case '?': return 0xF4;
case '"': return 0xF6; // 0xF5 is opening quote
case '~': return 0xF7;
case '*': return 0xFB;
case ' ': return DIALOG_CHAR_SPACE;
case '\n': return DIALOG_CHAR_NEWLINE;
case '\0': return DIALOG_CHAR_TERMINATOR;
default: return ((u8)c < 0xF0) ? ASCII_TO_DIALOG(c) : c;
}
}
void str_ascii_to_dialog(const char* string, u8* dialog, u16 length) {
for (int i = 0; i < length; i++) {
switch (string[i]) {
case '\'': dialog[i] = 0x3E; break;
case '.': dialog[i] = 0x3F; break;
case ',': dialog[i] = DIALOG_CHAR_COMMA; break;
case '-': dialog[i] = 0x9F; break;
case '(': dialog[i] = 0xE1; break;
case ')': dialog[i] = 0xE3; break;
case '&': dialog[i] = 0xE5; break;
case '!': dialog[i] = 0xF2; break;
case '%': dialog[i] = 0xF3; break;
case '?': dialog[i] = 0xF4; break;
case '"': dialog[i] = 0xF6; break; // 0xF5 is opening quote
case '~': dialog[i] = 0xF7; break;
case '*': dialog[i] = 0xFB; break;
case ' ': dialog[i] = DIALOG_CHAR_SPACE; break;
case '\n': dialog[i] = DIALOG_CHAR_NEWLINE; break;
default: dialog[i] = ((u8)string[i] < 0xF0) ? ASCII_TO_DIALOG(string[i]) : string[i];
}
dialog[i] = str_ascii_char_to_dialog(string[i]);
}
dialog[length] = DIALOG_CHAR_TERMINATOR;
}
@ -2731,9 +2733,6 @@ s16 render_pause_courses_and_castle(void) {
#ifdef VERSION_EU
gInGameLanguage = eu_get_language();
#endif
#ifdef EXT_OPTIONS_MENU
if (optmenu_open == 0) {
#endif
switch (gDialogBoxState) {
case DIALOG_STATE_OPENING:
@ -2811,14 +2810,10 @@ s16 render_pause_courses_and_castle(void) {
if (gDialogTextAlpha < 250) {
gDialogTextAlpha += 25;
}
#ifdef EXT_OPTIONS_MENU
} else {
shade_screen();
optmenu_draw();
}
optmenu_check_buttons();
optmenu_draw_prompt();
#endif
if (gDjuiPanelPauseCreated) { shade_screen(); }
if (gPlayer1Controller->buttonPressed & R_TRIG)
djui_panel_pause_create(NULL);
return 0;
}
@ -3109,8 +3104,8 @@ void render_save_confirmation(s16 x, s16 y, s8 *index, s16 sp6e)
s16 xOffset = get_str_x_pos_from_center(160, textContinueWithoutSaveArr[gInGameLanguage], 12.0f);
#else
u8 textSaveAndContinue[] = { TEXT_SAVE_AND_CONTINUE };
u8 textSaveAndQuit[] = { TEXT_SAVE_AND_QUIT };
u8 textSaveExitGame[] = { TEXT_SAVE_EXIT_GAME };
//u8 textSaveAndQuit[] = { TEXT_SAVE_AND_QUIT };
//u8 textSaveExitGame[] = { TEXT_SAVE_EXIT_GAME };
u8 textContinueWithoutSave[] = { TEXT_CONTINUE_WITHOUT_SAVING };
#endif
@ -3195,8 +3190,6 @@ s16 render_menus_and_dialogs() {
create_dl_ortho_matrix();
render_chat();
if (gMenuMode != -1) {
switch (gMenuMode) {
case 0:

View file

@ -30,6 +30,10 @@
#define RENDER_COURSE_DONE_SCREEN 2
#if !defined(VERSION_JP) && !defined(VERSION_SH)
extern u8 gDialogCharWidths[];
#endif
extern s8 gDialogCourseActNum;
extern s8 gHudFlash;
@ -117,6 +121,7 @@ void create_dl_identity_matrix(void);
void create_dl_translation_matrix(s8 pushOp, f32 x, f32 y, f32 z);
void create_dl_ortho_matrix(void);
void render_generic_char(u8 c);
u8 str_ascii_char_to_dialog(char c);
void str_ascii_to_dialog(const char* string, u8* dialog, u16 length);
f32 get_generic_dialog_width(u8* dialog);
f32 get_generic_ascii_string_width(const char* ascii);

View file

@ -35,6 +35,7 @@
#include "pc/cliopts.h"
#include "pc/configfile.h"
#include "pc/network/network.h"
#include "pc/djui/djui.h"
#include "game/screen_transition.h"
@ -218,6 +219,13 @@ u32 pressed_pause(void) {
}
void set_play_mode(s16 playMode) {
if (sCurrPlayMode == PLAY_MODE_PAUSED && playMode != PLAY_MODE_PAUSED) {
djui_base_set_visible(&gDjuiPauseOptions->base, false);
}
if (playMode == PLAY_MODE_PAUSED && sCurrPlayMode != PLAY_MODE_PAUSED) {
djui_base_set_visible(&gDjuiPauseOptions->base, true);
}
sCurrPlayMode = playMode;
D_80339ECA = 0;
}
@ -1306,7 +1314,8 @@ s32 init_level(void) {
set_mario_action(gMarioState, ACT_IDLE, 0);
} else if (gDebugLevelSelect == 0) {
if (gMarioState->action != ACT_UNINITIALIZED) {
if (save_file_exists(gCurrSaveFileNum - 1)) {
bool skipIntro = (gNetworkType == NT_NONE);
if (save_file_exists(gCurrSaveFileNum - 1) || skipIntro) {
set_mario_action(gMarioState, ACT_IDLE, 0);
} else if (gCLIOpts.SkipIntro == 0 && configSkipIntro == 0 && gServerSettings.skipIntro == 0) {
set_mario_action(gMarioState, ACT_INTRO_CUTSCENE, 0);
@ -1377,6 +1386,7 @@ s32 lvl_init_from_save_file(UNUSED s16 arg0, s32 levelNum) {
sWarpDest.type = WARP_TYPE_NOT_WARPING;
sDelayedWarpOp = WARP_OP_NONE;
gShouldNotPlayCastleMusic = !save_file_exists(gCurrSaveFileNum - 1) && gCLIOpts.SkipIntro == 0 && configSkipIntro == 0;
if (gNetworkType == NT_NONE) { gShouldNotPlayCastleMusic = true; }
gCurrLevelNum = levelNum;
gCurrCourseNum = COURSE_NONE;

View file

@ -1867,7 +1867,7 @@ s32 execute_mario_action(UNUSED struct Object *o) {
s32 inLoop = TRUE;
// hide inactive players
struct NetworkPlayer* np = &gNetworkPlayers[gMarioState->playerIndex];
if (np->type != NPT_LOCAL) {
if (gMarioState->playerIndex != 0 && gNetworkPlayerLocal != NULL) {
bool levelAreaMismatch =
(np->currCourseNum != gNetworkPlayerLocal->currCourseNum
|| np->currActNum != gNetworkPlayerLocal->currActNum

View file

@ -514,10 +514,13 @@ s32 is_point_within_radius_of_mario(f32 x, f32 y, f32 z, s32 dist) {
}
u8 is_player_active(struct MarioState* m) {
if (gNetworkType == NT_NONE && m == &gMarioStates[0]) { return TRUE; }
if (m->action == ACT_BUBBLED) { return FALSE; }
struct NetworkPlayer* np = &gNetworkPlayers[m->playerIndex];
if (np->type != NPT_LOCAL) {
if (!np->connected) { return FALSE; }
if (gNetworkPlayerLocal == NULL) { return FALSE; }
bool levelAreaMismatch =
(np->currCourseNum != gNetworkPlayerLocal->currCourseNum
|| np->currActNum != gNetworkPlayerLocal->currActNum

View file

@ -1,634 +0,0 @@
#ifdef EXT_OPTIONS_MENU
#include "sm64.h"
#include "include/text_strings.h"
#include "engine/math_util.h"
#include "audio/external.h"
#include "game/camera.h"
#include "game/level_update.h"
#include "game/print.h"
#include "game/segment2.h"
#include "game/save_file.h"
#ifdef BETTERCAMERA
#include "game/bettercamera.h"
#endif
#include "game/mario_misc.h"
#include "game/game_init.h"
#include "game/ingame_menu.h"
#include "game/options_menu.h"
#include "pc/pc_main.h"
#include "pc/cliopts.h"
#include "pc/cheats.h"
#include "pc/configfile.h"
#include "pc/controller/controller_api.h"
#include <stdbool.h>
#include "../../include/libc/stdlib.h"
u8 optmenu_open = 0;
static u8 optmenu_binding = 0;
static u8 optmenu_bind_idx = 0;
/* Keeps track of how many times the user has pressed L while in the options menu, so cheats can be unlocked */
static s32 l_counter = 0;
// How to add stuff:
// strings: add them to include/text_strings.h.in
// and to menuStr[] / opts*Str[]
// options: add them to the relevant options list
// menus: add a new submenu definition and a new
// option to the optsMain list
static const u8 toggleStr[][16] = {
{ TEXT_OPT_DISABLED },
{ TEXT_OPT_ENABLED },
};
static const u8 menuStr[][32] = {
{ TEXT_OPT_HIGHLIGHT },
{ TEXT_OPT_BUTTON1 },
{ TEXT_OPT_BUTTON2 },
{ TEXT_OPT_OPTIONS },
{ TEXT_OPT_CAMERA },
{ TEXT_OPT_CONTROLS },
{ TEXT_OPT_VIDEO },
{ TEXT_OPT_AUDIO },
{ TEXT_EXIT_GAME },
{ TEXT_OPT_CHEATS },
};
static const u8 optsCameraStr[][32] = {
{ TEXT_OPT_CAMX },
{ TEXT_OPT_CAMY },
{ TEXT_OPT_INVERTX },
{ TEXT_OPT_INVERTY },
{ TEXT_OPT_CAMC },
{ TEXT_OPT_CAMP },
{ TEXT_OPT_ANALOGUE },
{ TEXT_OPT_MOUSE },
{ TEXT_OPT_CAMD },
{ TEXT_OPT_CAMON },
};
static const u8 optsVideoStr[][32] = {
{ TEXT_OPT_FSCREEN },
{ TEXT_OPT_TEXFILTER },
{ TEXT_OPT_NEAREST },
{ TEXT_OPT_LINEAR },
{ TEXT_OPT_RESETWND },
{ TEXT_OPT_VSYNC },
{ TEXT_OPT_AUTO },
{ TEXT_OPT_HUD },
{ TEXT_OPT_THREEPT },
{ TEXT_OPT_APPLY },
};
static const u8 optsAudioStr[][32] = {
{ TEXT_OPT_MVOLUME },
{ TEXT_OPT_MUSVOLUME },
{ TEXT_OPT_SFXVOLUME },
{ TEXT_OPT_ENVVOLUME },
{ TEXT_OPT_LUIGISND },
};
static const u8 optsCheatsStr[][64] = {
{ TEXT_OPT_CHEAT1 },
{ TEXT_OPT_CHEAT2 },
{ TEXT_OPT_CHEAT3 },
{ TEXT_OPT_CHEAT4 },
{ TEXT_OPT_CHEAT5 },
{ TEXT_OPT_CHEAT6 },
{ TEXT_OPT_CHEAT7 },
{ TEXT_OPT_CHEAT8 },
{ TEXT_OPT_CHEAT9 },
};
#define TEXT_BIND_CHAT 0x0C,0x2B,0x24,0x37,0xFF
static const u8 bindStr[][32] = {
{ TEXT_OPT_UNBOUND },
{ TEXT_OPT_PRESSKEY },
{ TEXT_BIND_A },
{ TEXT_BIND_B },
{ TEXT_BIND_START },
{ TEXT_BIND_L },
{ TEXT_BIND_R },
{ TEXT_BIND_Z },
{ TEXT_BIND_C_UP },
{ TEXT_BIND_C_DOWN },
{ TEXT_BIND_C_LEFT },
{ TEXT_BIND_C_RIGHT },
{ TEXT_BIND_UP },
{ TEXT_BIND_DOWN },
{ TEXT_BIND_LEFT },
{ TEXT_BIND_RIGHT },
{ TEXT_BIND_CHAT },
{ TEXT_OPT_DEADZONE },
{ TEXT_OPT_RUMBLE }
};
static const u8 *filterChoices[] = {
optsVideoStr[2],
optsVideoStr[3],
optsVideoStr[8],
};
static const u8 *vsyncChoices[] = {
toggleStr[0],
toggleStr[1],
optsVideoStr[6],
};
enum OptType {
OPT_INVALID = 0,
OPT_TOGGLE,
OPT_CHOICE,
OPT_SCROLL,
OPT_SUBMENU,
OPT_BIND,
OPT_BUTTON,
};
struct SubMenu;
struct Option {
enum OptType type;
const u8 *label;
union {
u32 *uval;
bool *bval;
};
union {
struct {
const u8 **choices;
u32 numChoices;
};
struct {
u32 scrMin;
u32 scrMax;
u32 scrStep;
};
struct SubMenu *nextMenu;
void (*actionFn)(struct Option *, s32);
};
};
struct SubMenu {
struct SubMenu *prev; // this is set at runtime to avoid needless complication
const u8 *label;
struct Option *opts;
s32 numOpts;
s32 select;
s32 scroll;
};
/* helper macros */
#define DEF_OPT_TOGGLE(lbl, bv) \
{ .type = OPT_TOGGLE, .label = lbl, .bval = bv }
#define DEF_OPT_SCROLL(lbl, uv, min, max, st) \
{ .type = OPT_SCROLL, .label = lbl, .uval = uv, .scrMin = min, .scrMax = max, .scrStep = st }
#define DEF_OPT_CHOICE(lbl, uv, ch) \
{ .type = OPT_CHOICE, .label = lbl, .uval = uv, .choices = ch, .numChoices = sizeof(ch) / sizeof(ch[0]) }
#define DEF_OPT_SUBMENU(lbl, nm) \
{ .type = OPT_SUBMENU, .label = lbl, .nextMenu = nm }
#define DEF_OPT_BIND(lbl, uv) \
{ .type = OPT_BIND, .label = lbl, .uval = uv }
#define DEF_OPT_BUTTON(lbl, act) \
{ .type = OPT_BUTTON, .label = lbl, .actionFn = act }
#define DEF_SUBMENU(lbl, opt) \
{ .label = lbl, .opts = opt, .numOpts = sizeof(opt) / sizeof(opt[0]) }
/* button action functions */
static void optmenu_act_exit(UNUSED struct Option *self, s32 arg) {
if (!arg) game_exit(); // only exit on A press and not directions
}
static void optvideo_reset_window(UNUSED struct Option *self, s32 arg) {
if (!arg) {
// Restrict reset to A press and not directions
configWindow.reset = true;
configWindow.settings_changed = true;
}
}
static void optvideo_apply(UNUSED struct Option *self, s32 arg) {
if (!arg) configWindow.settings_changed = true;
}
/* submenu option lists */
#ifdef BETTERCAMERA
static struct Option optsCamera[] = {
DEF_OPT_TOGGLE( optsCameraStr[9], &configEnableCamera ),
DEF_OPT_TOGGLE( optsCameraStr[6], &configCameraAnalog ),
DEF_OPT_TOGGLE( optsCameraStr[7], &configCameraMouse ),
DEF_OPT_TOGGLE( optsCameraStr[2], &configCameraInvertX ),
DEF_OPT_TOGGLE( optsCameraStr[3], &configCameraInvertY ),
DEF_OPT_SCROLL( optsCameraStr[0], &configCameraXSens, 1, 100, 1 ),
DEF_OPT_SCROLL( optsCameraStr[1], &configCameraYSens, 1, 100, 1 ),
DEF_OPT_SCROLL( optsCameraStr[4], &configCameraAggr, 0, 100, 1 ),
DEF_OPT_SCROLL( optsCameraStr[5], &configCameraPan, 0, 100, 1 ),
DEF_OPT_SCROLL( optsCameraStr[8], &configCameraDegrade, 0, 100, 1 ),
};
#endif
static struct Option optsControls[] = {
DEF_OPT_BIND( bindStr[ 2], configKeyA ),
DEF_OPT_BIND( bindStr[ 3], configKeyB ),
DEF_OPT_BIND( bindStr[ 4], configKeyStart ),
DEF_OPT_BIND( bindStr[ 5], configKeyL ),
DEF_OPT_BIND( bindStr[ 6], configKeyR ),
DEF_OPT_BIND( bindStr[ 7], configKeyZ ),
DEF_OPT_BIND( bindStr[ 8], configKeyCUp ),
DEF_OPT_BIND( bindStr[ 9], configKeyCDown ),
DEF_OPT_BIND( bindStr[10], configKeyCLeft ),
DEF_OPT_BIND( bindStr[11], configKeyCRight ),
DEF_OPT_BIND( bindStr[12], configKeyStickUp ),
DEF_OPT_BIND( bindStr[13], configKeyStickDown ),
DEF_OPT_BIND( bindStr[14], configKeyStickLeft ),
DEF_OPT_BIND( bindStr[15], configKeyStickRight ),
DEF_OPT_BIND( bindStr[16], configKeyChat ),
// max deadzone is 31000; this is less than the max range of ~32768, but this
// way, the player can't accidentally lock themselves out of using the stick
DEF_OPT_SCROLL( bindStr[17], &configStickDeadzone, 0, 100, 1 ),
DEF_OPT_SCROLL( bindStr[18], &configRumbleStrength, 0, 100, 1)
};
static struct Option optsVideo[] = {
DEF_OPT_TOGGLE( optsVideoStr[0], &configWindow.fullscreen ),
DEF_OPT_TOGGLE( optsVideoStr[5], &configWindow.vsync ),
DEF_OPT_CHOICE( optsVideoStr[1], &configFiltering, filterChoices ),
DEF_OPT_TOGGLE( optsVideoStr[7], &configHUD ),
DEF_OPT_BUTTON( optsVideoStr[4], optvideo_reset_window ),
DEF_OPT_BUTTON( optsVideoStr[9], optvideo_apply ),
};
static struct Option optsAudio[] = {
DEF_OPT_SCROLL( optsAudioStr[0], &configMasterVolume, 0, MAX_VOLUME, 1 ),
DEF_OPT_SCROLL( optsAudioStr[1], &configMusicVolume, 0, MAX_VOLUME, 1),
DEF_OPT_SCROLL( optsAudioStr[2], &configSfxVolume, 0, MAX_VOLUME, 1),
DEF_OPT_SCROLL( optsAudioStr[3], &configEnvVolume, 0, MAX_VOLUME, 1),
DEF_OPT_TOGGLE( optsAudioStr[4], &configLuigiSounds ),
};
static struct Option optsCheats[] = {
DEF_OPT_TOGGLE( optsCheatsStr[0], &Cheats.EnableCheats ),
DEF_OPT_TOGGLE( optsCheatsStr[1], &Cheats.MoonJump ),
DEF_OPT_TOGGLE( optsCheatsStr[2], &Cheats.GodMode ),
DEF_OPT_TOGGLE( optsCheatsStr[3], &Cheats.InfiniteLives ),
DEF_OPT_TOGGLE( optsCheatsStr[4], &Cheats.SuperSpeed ),
DEF_OPT_TOGGLE( optsCheatsStr[5], &Cheats.Responsive ),
};
/* submenu definitions */
#ifdef BETTERCAMERA
static struct SubMenu menuCamera = DEF_SUBMENU( menuStr[4], optsCamera );
#endif
static struct SubMenu menuControls = DEF_SUBMENU( menuStr[5], optsControls );
static struct SubMenu menuVideo = DEF_SUBMENU( menuStr[6], optsVideo );
static struct SubMenu menuAudio = DEF_SUBMENU( menuStr[7], optsAudio );
static struct SubMenu menuCheats = DEF_SUBMENU( menuStr[9], optsCheats );
/* main options menu definition */
static struct Option optsMain[] = {
#ifdef BETTERCAMERA
DEF_OPT_SUBMENU( menuStr[4], &menuCamera ),
#endif
DEF_OPT_SUBMENU( menuStr[5], &menuControls ),
DEF_OPT_SUBMENU( menuStr[6], &menuVideo ),
DEF_OPT_SUBMENU( menuStr[7], &menuAudio ),
DEF_OPT_BUTTON ( menuStr[8], optmenu_act_exit ),
// NOTE: always keep cheats the last option here because of the half-assed way I toggle them
DEF_OPT_SUBMENU( menuStr[9], &menuCheats )
};
static struct SubMenu menuMain = DEF_SUBMENU( menuStr[3], optsMain );
/* implementation */
static s32 optmenu_option_timer = 0;
static u8 optmenu_hold_count = 0;
static struct SubMenu *currentMenu = &menuMain;
static inline s32 wrap_add(s32 a, const s32 b, const s32 min, const s32 max) {
a += b;
if (a < min) a = max - (min - a) + 1;
else if (a > max) a = min + (a - max) - 1;
return a;
}
static void uint_to_hex(u32 num, u8 *dst) {
u8 places = 4;
while (places--) {
const u32 digit = num & 0xF;
dst[places] = digit;
num >>= 4;
}
dst[4] = DIALOG_CHAR_TERMINATOR;
}
//Displays a box.
static void optmenu_draw_box(s16 x1, s16 y1, s16 x2, s16 y2, u8 r, u8 g, u8 b) {
gDPPipeSync(gDisplayListHead++);
gDPSetRenderMode(gDisplayListHead++, G_RM_OPA_SURF, G_RM_OPA_SURF2);
gDPSetCycleType(gDisplayListHead++, G_CYC_FILL);
gDPSetFillColor(gDisplayListHead++, GPACK_RGBA5551(r, g, b, 255));
gDPFillRectangle(gDisplayListHead++, x1, y1, x2 - 1, y2 - 1);
gDPPipeSync(gDisplayListHead++);
gDPSetCycleType(gDisplayListHead++, G_CYC_1CYCLE);
}
static void optmenu_draw_text(s16 x, s16 y, const u8 *str, u8 col) {
const u8 textX = get_str_x_pos_from_center(x, (u8*)str, 10.0f);
gDPSetEnvColor(gDisplayListHead++, 0, 0, 0, 255);
print_generic_string(textX+1, y-1, str);
if (col == 0) {
gDPSetEnvColor(gDisplayListHead++, 255, 255, 255, 255);
} else {
gDPSetEnvColor(gDisplayListHead++, 255, 32, 32, 255);
}
print_generic_string(textX, y, str);
}
static void optmenu_draw_opt(const struct Option *opt, s16 x, s16 y, u8 sel) {
u8 buf[32] = { 0 };
if (opt->type == OPT_SUBMENU || opt->type == OPT_BUTTON)
y -= 6;
optmenu_draw_text(x, y, opt->label, sel);
switch (opt->type) {
case OPT_TOGGLE:
optmenu_draw_text(x, y-13, toggleStr[(int)*opt->bval], sel);
break;
case OPT_CHOICE:
optmenu_draw_text(x, y-13, opt->choices[*opt->uval], sel);
break;
case OPT_SCROLL:
int_to_str(*opt->uval, buf);
optmenu_draw_text(x, y-13, buf, sel);
break;
case OPT_BIND:
x = 112;
for (u8 i = 0; i < MAX_BINDS; ++i, x += 48) {
const u8 white = (sel && (optmenu_bind_idx == i));
// TODO: button names
if (opt->uval[i] == VK_INVALID) {
if (optmenu_binding && white)
optmenu_draw_text(x, y-13, bindStr[1], 1);
else
optmenu_draw_text(x, y-13, bindStr[0], white);
} else {
uint_to_hex(opt->uval[i], buf);
optmenu_draw_text(x, y-13, buf, white);
}
}
break;
default: break;
};
}
static void optmenu_opt_change(struct Option *opt, s32 val) {
switch (opt->type) {
case OPT_TOGGLE:
*opt->bval = !*opt->bval;
break;
case OPT_CHOICE:
*opt->uval = wrap_add(*opt->uval, val, 0, opt->numChoices - 1);
break;
case OPT_SCROLL:
*opt->uval = wrap_add(*opt->uval, opt->scrStep * val, opt->scrMin, opt->scrMax);
break;
case OPT_SUBMENU:
opt->nextMenu->prev = currentMenu;
currentMenu = opt->nextMenu;
break;
case OPT_BUTTON:
if (opt->actionFn)
opt->actionFn(opt, val);
break;
case OPT_BIND:
if (val == 0xFF) {
// clear the bind
opt->uval[optmenu_bind_idx] = VK_INVALID;
} else if (val == 0) {
opt->uval[optmenu_bind_idx] = VK_INVALID;
optmenu_binding = 1;
controller_get_raw_key(); // clear the last key, which is probably A
} else {
optmenu_bind_idx = wrap_add(optmenu_bind_idx, val, 0, MAX_BINDS - 1);
}
break;
default: break;
}
}
static inline s16 get_hudstr_centered_x(const s16 sx, const u8 *str) {
const u8 *chr = str;
s16 len = 0;
while (*chr != GLOBAR_CHAR_TERMINATOR) ++chr, ++len;
return sx - len * 6; // stride is 12
}
//Options menu
void optmenu_draw(void) {
s16 scroll;
s16 scrollpos;
const s16 labelX = get_hudstr_centered_x(160, currentMenu->label);
gSPDisplayList(gDisplayListHead++, dl_rgba16_text_begin);
gDPSetEnvColor(gDisplayListHead++, 255, 255, 255, 255);
print_hud_lut_string(HUD_LUT_GLOBAL, labelX, 40, currentMenu->label);
gSPDisplayList(gDisplayListHead++, dl_rgba16_text_end);
if (currentMenu->numOpts > 4) {
optmenu_draw_box(272, 90, 280, 208, 0x80, 0x80, 0x80);
scrollpos = 54 * ((f32)currentMenu->scroll / (currentMenu->numOpts-4));
optmenu_draw_box(272, 90+scrollpos, 280, 154+scrollpos, 0xFF, 0xFF, 0xFF);
}
gSPDisplayList(gDisplayListHead++, dl_ia_text_begin);
gDPSetScissor(gDisplayListHead++, G_SC_NON_INTERLACE, 0, 80, SCREEN_WIDTH, SCREEN_HEIGHT);
for (u8 i = 0; i < currentMenu->numOpts; i++) {
scroll = 140 - 32 * i + currentMenu->scroll * 32;
// FIXME: just start from the first visible option bruh
if (scroll <= 140 && scroll > 32)
optmenu_draw_opt(&currentMenu->opts[i], 160, scroll, (currentMenu->select == i));
}
gDPSetScissor(gDisplayListHead++, G_SC_NON_INTERLACE, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
gSPDisplayList(gDisplayListHead++, dl_ia_text_end);
gDPSetEnvColor(gDisplayListHead++, 255, 255, 255, 255);
gSPDisplayList(gDisplayListHead++, dl_rgba16_text_begin);
print_hud_lut_string(HUD_LUT_GLOBAL, 80, 90 + (32 * (currentMenu->select - currentMenu->scroll)), menuStr[0]);
print_hud_lut_string(HUD_LUT_GLOBAL, 224, 90 + (32 * (currentMenu->select - currentMenu->scroll)), menuStr[0]);
gSPDisplayList(gDisplayListHead++, dl_rgba16_text_end);
}
//This has been separated for interesting reasons. Don't question it.
void optmenu_draw_prompt(void) {
gSPDisplayList(gDisplayListHead++, dl_ia_text_begin);
optmenu_draw_text(264, 212, menuStr[1 + optmenu_open], 0);
gSPDisplayList(gDisplayListHead++, dl_ia_text_end);
}
void optmenu_toggle(void) {
if (optmenu_open == 0) {
#ifndef nosound
play_sound(SOUND_MENU_CHANGE_SELECT, gDefaultSoundArgs);
#endif
// HACK: hide the last option in main if cheats are disabled
menuMain.numOpts = sizeof(optsMain) / sizeof(optsMain[0]);
if (!Cheats.EnableCheats) {
menuMain.numOpts--;
if (menuMain.select >= menuMain.numOpts) {
menuMain.select = 0; // don't bother
menuMain.scroll = 0;
}
}
currentMenu = &menuMain;
optmenu_open = 1;
/* Resets l_counter to 0 every time the options menu is open */
l_counter = 0;
} else {
#ifndef nosound
play_sound(SOUND_MENU_MARIO_CASTLE_WARP2, gDefaultSoundArgs);
#endif
optmenu_open = 0;
#ifdef BETTERCAMERA
newcam_init_settings(); // load bettercam settings from config vars
#endif
controller_reconfigure(); // rebind using new config values
configfile_save(configfile_name());
}
}
void optmenu_check_buttons(void) {
if (optmenu_binding) {
u32 key = controller_get_raw_key();
if (key != VK_INVALID) {
#ifndef nosound
play_sound(SOUND_MENU_CHANGE_SELECT, gDefaultSoundArgs);
#endif
currentMenu->opts[currentMenu->select].uval[optmenu_bind_idx] = key;
optmenu_binding = 0;
optmenu_option_timer = 12;
}
return;
}
if (gPlayer1Controller->buttonPressed & R_TRIG)
optmenu_toggle();
/* Enables cheats if the user press the L trigger 3 times while in the options menu. Also plays a sound. */
if ((gPlayer1Controller->buttonPressed & L_TRIG) && !Cheats.EnableCheats) {
if (l_counter == 2) {
Cheats.EnableCheats = true;
play_sound(SOUND_MENU_STAR_SOUND, gDefaultSoundArgs);
l_counter = 0;
} else {
l_counter++;
}
}
if (!optmenu_open) return;
u8 allowInput = 0;
optmenu_option_timer--;
if (optmenu_option_timer <= 0) {
if (optmenu_hold_count == 0) {
optmenu_hold_count++;
optmenu_option_timer = 10;
} else {
optmenu_option_timer = 3;
}
allowInput = 1;
}
if (ABS(gPlayer1Controller->stickY) > 60) {
if (allowInput) {
#ifndef nosound
play_sound(SOUND_MENU_CHANGE_SELECT, gDefaultSoundArgs);
#endif
if (gPlayer1Controller->stickY >= 60) {
currentMenu->select--;
if (currentMenu->select < 0)
currentMenu->select = currentMenu->numOpts-1;
} else {
currentMenu->select++;
if (currentMenu->select >= currentMenu->numOpts)
currentMenu->select = 0;
}
if (currentMenu->select < currentMenu->scroll)
currentMenu->scroll = currentMenu->select;
else if (currentMenu->select > currentMenu->scroll + 3)
currentMenu->scroll = currentMenu->select - 3;
}
} else if (ABS(gPlayer1Controller->stickX) > 60) {
if (allowInput) {
#ifndef nosound
play_sound(SOUND_MENU_CHANGE_SELECT, gDefaultSoundArgs);
#endif
if (gPlayer1Controller->stickX >= 60)
optmenu_opt_change(&currentMenu->opts[currentMenu->select], 1);
else
optmenu_opt_change(&currentMenu->opts[currentMenu->select], -1);
}
} else if (gPlayer1Controller->buttonPressed & A_BUTTON) {
if (allowInput) {
#ifndef nosound
play_sound(SOUND_MENU_CHANGE_SELECT, gDefaultSoundArgs);
#endif
optmenu_opt_change(&currentMenu->opts[currentMenu->select], 0);
}
} else if (gPlayer1Controller->buttonPressed & B_BUTTON) {
if (allowInput) {
if (currentMenu->prev) {
#ifndef nosound
play_sound(SOUND_MENU_CHANGE_SELECT, gDefaultSoundArgs);
#endif
currentMenu = currentMenu->prev;
} else {
// can't go back, exit the menu altogether
optmenu_toggle();
}
}
} else if (gPlayer1Controller->buttonPressed & Z_TRIG) {
// HACK: clear binds with Z
if (allowInput && currentMenu->opts[currentMenu->select].type == OPT_BIND)
optmenu_opt_change(&currentMenu->opts[currentMenu->select], 0xFF);
} else if (gPlayer1Controller->buttonPressed & START_BUTTON) {
if (allowInput) optmenu_toggle();
} else {
optmenu_hold_count = 0;
optmenu_option_timer = 0;
}
}
#endif // EXT_OPTIONS_MENU

View file

@ -1,11 +0,0 @@
#ifndef OPTIONS_MENU_H
#define OPTIONS_MENU_H
void optmenu_toggle(void);
void optmenu_draw(void);
void optmenu_draw_prompt(void);
void optmenu_check_buttons(void);
extern u8 optmenu_open;
#endif // OPTIONS_MENU_H

View file

@ -199,7 +199,7 @@ void unload_object(struct Object *obj) {
obj->header.gfx.node.flags &= ~GRAPH_RENDER_CYLBOARD;
obj->header.gfx.node.flags &= ~GRAPH_RENDER_ACTIVE;
if (obj->oSyncID != 0) {
if (obj->oSyncID != 0 && gNetworkType != NT_NONE) {
if (gSyncObjects[obj->oSyncID].syncDeathEvent) {
network_send_object(obj);
} else {

View file

@ -227,7 +227,7 @@ static Gfx gd_texture1_dummy_aligner1[] = { // @ 801A8728
gsSPEndDisplayList(),
};
ALIGNED8 static u8 gd_texture_hand_open[] = {
ALIGNED8 u8 gd_texture_hand_open[] = {
#include "textures/intro_raw/hand_open.rgba16.inc.c"
};
@ -235,7 +235,7 @@ static Gfx gd_texture2_dummy_aligner1[] = {
gsSPEndDisplayList()
};
ALIGNED8 static u8 gd_texture_hand_closed[] = {
ALIGNED8 u8 gd_texture_hand_closed[] = {
#include "textures/intro_raw/hand_closed.rgba16.inc.c"
};

View file

@ -1,326 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "custom_menu.h"
#include "custom_menu_system.h"
#include "pc/network/network.h"
#include "pc/configfile.h"
#include "pc/controller/controller_keyboard.h"
#include "game/object_list_processor.h"
#include "game/object_helpers.h"
#include "game/ingame_menu.h"
#include "game/game_init.h"
#include "game/segment2.h"
#include "object_fields.h"
#include "model_ids.h"
#include "behavior_data.h"
#include "audio_defines.h"
#include "audio/external.h"
#include "config.h"
#include "pc/network/version.h"
#ifdef DISCORD_SDK
#include "pc/network/discord/discord.h"
#endif
#define MAIN_MENU_HEADER_TEXT "SM64 COOP"
char sConnectionJoinError[128] = { 0 };
char gConnectionText[128] = { 0 };
struct CustomMenu* sConnectMenu = NULL;
u8 gOpenConnectMenu = FALSE;
s8 sGotoGame = 0;
static void menu_main_draw_strings(void) {
char* subtitle = "Still in development.";
s16 subtitleX = (SCREEN_WIDTH - get_generic_ascii_string_width(subtitle)) / 2;
print_generic_ascii_string(subtitleX, 150, subtitle);
char* versionString = get_version();
gDPSetEnvColor(gDisplayListHead++, 255, 255, 255, 120);
print_generic_ascii_string(25, 25, versionString);
}
static void host_menu_draw_strings(void) {
#ifdef DISCORD_SDK
#define HOST_MENU_MAX_ITEMS 6
#else
#define HOST_MENU_MAX_ITEMS 5
#endif
// set up server setting strings
char* buttonText[HOST_MENU_MAX_ITEMS];
switch (configPlayerInteraction) {
case 0: buttonText[0] = "Non-solid players."; break;
case 1: buttonText[0] = "Solid players."; break;
case 2: buttonText[0] = "Friendly fire."; break;
default: buttonText[0] = "UNKNOWN"; break;
}
if (configPlayerKnockbackStrength <= 20) {
buttonText[1] = "Weak knockback.";
} else if (configPlayerKnockbackStrength <= 40) {
buttonText[1] = "Normal knockback.";
} else {
buttonText[1] = "Too much knockback.";
}
buttonText[2] = configStayInLevelAfterStar ? "Stay in level after star." : "Leave level after star.";
buttonText[3] = configSkipIntro ? "Skip intro cutscene." : "Play intro cutscene.";
buttonText[4] = configShareLives ? "Share lives." : "Lives are not shared.";
#ifdef DISCORD_SDK
buttonText[5] = (configNetworkSystem == 0) ? "Host through Discord." : "Host direct connection.";
#endif
// display server setting strings
for (int i = 0; i < HOST_MENU_MAX_ITEMS; i++) {
print_generic_ascii_string(95, 173 + -29 * i, buttonText[i]);
}
// display direct connection warning
if (configNetworkSystem != 0) {
f32 red = (f32)fabs(sin(gGlobalTimer / 20.0f));
gDPSetEnvColor(gDisplayListHead++, 222, 222 * red, 222 * red, gMenuStringAlpha);
char warning[128];
snprintf(warning, 127, "Port forward '%d' in network router settings or use Hamachi.", configHostPort);
print_generic_ascii_string(0, 5, warning);
}
#ifdef DISCORD_SDK
else if ((configNetworkSystem == 0) && gDiscordFailed) {
f32 red = (f32)fabs(sin(gGlobalTimer / 20.0f));
gDPSetEnvColor(gDisplayListHead++, 222, 222 * red, 222 * red, gMenuStringAlpha);
char warning[128];
snprintf(warning, 127, "Discord failed to initialize.");
print_generic_ascii_string(0, 15, warning);
}
#endif
}
static void host_menu_do_host(void) {
#ifndef DISCORD_SDK
configNetworkSystem = 1;
#endif
if (configNetworkSystem == 0) {
network_set_system(NS_DISCORD);
} else {
network_set_system(NS_SOCKET);
}
custom_menu_close_system();
}
static void host_menu_setting_network_system(void) {
#ifdef DISCORD_SDK
configNetworkSystem = (configNetworkSystem == 0) ? 1 : 0;
#else
configNetworkSystem = 1;
#endif
}
static void host_menu_setting_interaction(void) {
switch (configPlayerInteraction) {
case 0: configPlayerInteraction = 1; break;
case 1: configPlayerInteraction = 2; break;
default: configPlayerInteraction = 0; break;
}
}
static void host_menu_setting_knockback(void) {
if (configPlayerKnockbackStrength <= 20) {
configPlayerKnockbackStrength = 25;
} else if (configPlayerKnockbackStrength <= 40) {
configPlayerKnockbackStrength = 75;
} else {
configPlayerKnockbackStrength = 10;
}
}
static void host_menu_setting_stay_in_level(void) {
configStayInLevelAfterStar = (configStayInLevelAfterStar == 0) ? 1 : 0;
}
static void host_menu_setting_skip_intro(void) {
configSkipIntro = (configSkipIntro == 1) ? 0 : 1;
}
static void host_menu_setting_share_lives(void) {
configShareLives = (configShareLives == 0) ? 1 : 0;
}
#ifdef DISCORD_SDK
static void join_menu_draw_strings(void) {
print_generic_ascii_string(30, 155, "Accept a Discord game invite in order to join.");
print_generic_ascii_string(30, 130, "For direct connections, click connect to type in an IP.");
}
#endif
static void connect_menu_draw_strings(void) {
if (gNetworkType == NT_CLIENT) {
f32 alpha = (f32)fabs(sin(gGlobalTimer / 20.0f));
gDPSetEnvColor(gDisplayListHead++, 222, 222, 222, gMenuStringAlpha * alpha);
print_generic_ascii_string(130, 130, "Connecting...");
return;
}
if (*sConnectionJoinError) {
f32 red = (f32)fabs(sin(gGlobalTimer / 20.0f));
gDPSetEnvColor(gDisplayListHead++, 222, 222 * red, 222 * red, gMenuStringAlpha);
f32 messageX = (SCREEN_WIDTH - get_generic_ascii_string_width(sConnectionJoinError)) / 2.0;
f32 messageY = (SCREEN_HEIGHT + get_generic_ascii_string_height(sConnectionJoinError)) / 2.0;
print_generic_ascii_string(messageX, messageY, sConnectionJoinError);
return;
}
print_generic_ascii_string(30, 175, "Type in or paste the host's IP.");
print_generic_ascii_string(30, 160, "Note - the host must forward a port on their router.");
if (keyboard_in_text_input()) {
if (strlen(gTextInput) >= 7) {
print_generic_ascii_string(30, 100, "Press (ENTER) to connect.");
} else {
print_generic_ascii_string(30, 100, "Press (ESC) to cancel.");
}
}
gDPSetEnvColor(gDisplayListHead++, 130, 222, 140, gMenuStringAlpha);
print_generic_ascii_string(30, 130, gTextInput);
}
static void connect_menu_on_connection_attempt(void) {
play_sound(SOUND_GENERAL_COIN, gDefaultSoundArgs);
keyboard_stop_text_input();
if (gNetworkType != NT_NONE) { return; }
char delims[2] = " ";
// copy input
char buffer[MAX_TEXT_INPUT] = { 0 };
strncpy(buffer, gTextInput, MAX_TEXT_INPUT);
char* text = buffer;
// trim whitespace
while (*text == ' ') { text++; }
// grab IP
char* ip = strtok(text, delims);
if (ip == NULL) { custom_menu_close(); return; }
strncpy(configJoinIp, ip, MAX_CONFIG_STRING);
// grab port
char* port = strtok(NULL, delims);
if (port != NULL) {
unsigned int intPort = atoi(port);
if (intPort == 0 || intPort > 65535) { configJoinPort = DEFAULT_PORT; custom_menu_close(); return; }
configJoinPort = intPort;
}
else {
configJoinPort = DEFAULT_PORT;
}
network_set_system(NS_SOCKET);
network_init(NT_CLIENT);
}
static void connect_menu_on_click(void) {
sConnectionJoinError[0] = '\0';
keyboard_start_text_input(TIM_IP, MAX_TEXT_INPUT, custom_menu_close, connect_menu_on_connection_attempt);
// fill in our last attempt
if (configJoinPort == 0 || configJoinPort > 65535) { configJoinPort = DEFAULT_PORT; }
// only print custom port
if (configJoinPort == DEFAULT_PORT) {
sprintf(gTextInput, "%s", configJoinIp);
}
else {
sprintf(gTextInput, "%s %d", configJoinIp, configJoinPort);
}
}
static void connect_menu_on_close(void) {
keyboard_stop_text_input();
network_shutdown();
}
void custom_menu_init(struct CustomMenu* head) {
// set the header text
head->me->label = calloc(strlen(MAIN_MENU_HEADER_TEXT) + 1, sizeof(char));
strcpy(head->me->label, MAIN_MENU_HEADER_TEXT);
// set main menu settings
head->headerY = 55;
head->draw_strings = menu_main_draw_strings;
// create sub menus and buttons
struct CustomMenu* hostMenu = custom_menu_create(head, "HOST", -266, 0, gButtonScale.large);
hostMenu->headerY = 30;
hostMenu->draw_strings = host_menu_draw_strings;
custom_menu_create_button(hostMenu, "CANCEL", 700, -196 + (210 * 3), gButtonScale.large, SOUND_MENU_CAMERA_ZOOM_OUT, custom_menu_close);
custom_menu_create_button(hostMenu, "HOST", 700, -220, gButtonScale.large, SOUND_MENU_CAMERA_ZOOM_IN, host_menu_do_host);
custom_menu_create_button(hostMenu, "", -700, -180 + (210 * 3), gButtonScale.medium, SOUND_ACTION_BONK, host_menu_setting_interaction);
custom_menu_create_button(hostMenu, "", -700, -180 + (210 * 2), gButtonScale.medium, SOUND_ACTION_BONK, host_menu_setting_knockback);
custom_menu_create_button(hostMenu, "", -700, -180 + (210 * 1), gButtonScale.medium, SOUND_ACTION_BONK, host_menu_setting_stay_in_level);
custom_menu_create_button(hostMenu, "", -700, -180 + (210 * 0), gButtonScale.medium, SOUND_ACTION_BONK, host_menu_setting_skip_intro);
custom_menu_create_button(hostMenu, "", -700, -180 + (210 * -1), gButtonScale.medium, SOUND_ACTION_BONK, host_menu_setting_share_lives);
#ifdef DISCORD_SDK
custom_menu_create_button(hostMenu, "", -700, -180 + (210 * -2), gButtonScale.medium, SOUND_ACTION_BONK, host_menu_setting_network_system);
#endif
#ifdef DISCORD_SDK
struct CustomMenu* joinMenu = custom_menu_create(head, "JOIN", 266, 0, gButtonScale.large);
custom_menu_create_button(joinMenu, "CANCEL", -266, -320, gButtonScale.large, SOUND_MENU_CAMERA_ZOOM_OUT, custom_menu_close);
joinMenu->draw_strings = join_menu_draw_strings;
struct CustomMenu* connectMenu = custom_menu_create(joinMenu, "CONNECT", 266, -320, gButtonScale.large);
#else
struct CustomMenu* connectMenu = custom_menu_create(head, "CONNECT", 266, 0, gButtonScale.large);
#endif
connectMenu->me->on_click = connect_menu_on_click;
connectMenu->on_close = connect_menu_on_close;
connectMenu->draw_strings = connect_menu_draw_strings;
custom_menu_create_button(connectMenu, "CANCEL", 0, -400, gButtonScale.large, SOUND_MENU_CAMERA_ZOOM_OUT, custom_menu_close);
sConnectMenu = connectMenu;
}
void custom_menu_loop(void) {
// we've received an event that makes us exit the menus
if (sGotoGame) {
sSelectedFileNum = sGotoGame;
custom_menu_close_system();
}
// force-start the load when command-line server hosting
if (gNetworkType == NT_SERVER && sSelectedFileNum == 0) {
sSelectedFileNum = 1;
}
if (gOpenConnectMenu && sConnectMenu != NULL) {
gOpenConnectMenu = FALSE;
custom_menu_open(sConnectMenu);
}
}
void custom_menu_on_load_save_file(s8 saveFileNum) {
if (gNetworkType != NT_CLIENT && saveFileNum != 0) {
configHostSaveSlot = saveFileNum;
network_init(NT_SERVER);
}
}
void custom_menu_goto_game(s16 saveFileNum) {
sGotoGame = saveFileNum;
}
void custom_menu_connection_error(char* message) {
play_sound(SOUND_MARIO_MAMA_MIA, gDefaultSoundArgs);
strcpy(sConnectionJoinError, message);
network_shutdown();
}

View file

@ -1,13 +0,0 @@
#ifndef CUSTOM_MENU_H
#define CUSTOM_MENU_H
#include "custom_menu_system.h"
extern u8 gOpenConnectMenu;
void custom_menu_init(struct CustomMenu* head);
void custom_menu_loop(void);
void custom_menu_on_load_save_file(s8 saveFileNum);
void custom_menu_goto_game(s16 saveFileNum);
void custom_menu_connection_error(char* message);
#endif // CUSTOM_MENU_H

View file

@ -1,409 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "custom_menu_system.h"
#include "custom_menu.h"
#include "game/object_list_processor.h"
#include "game/object_helpers.h"
#include "game/ingame_menu.h"
#include "game/game_init.h"
#include "game/segment2.h"
#include "object_fields.h"
#include "model_ids.h"
#include "behavior_data.h"
#include "audio_defines.h"
#include "audio/external.h"
#include "gfx_dimensions.h"
#include "config.h"
static struct CustomMenu* sHead = NULL;
static struct CustomMenu* sCurrentMenu = NULL;
static struct CustomMenu* sLastMenu = NULL;
struct CustomMenuButtonScale gButtonScale = {
.small = 0.08111111f,
.medium = 0.09511111f,
.large = 0.11111111f,
};
u8 gMenuStringAlpha = 255;
struct ErrorDialog {
u8* dialog;
struct ErrorDialog* next;
};
static struct ErrorDialog* sErrorDialog = NULL;
struct CustomMenuButton* custom_menu_create_button(struct CustomMenu* parent, char* label, u16 x, u16 y, f32 scale, s32 clickSound, void (*on_click)(void)) {
struct CustomMenuButton* button = calloc(1, sizeof(struct CustomMenuButton));
if (parent->buttons == NULL) {
parent->buttons = button;
} else {
struct CustomMenuButton* parentButton = parent->buttons;
while (parentButton->next != NULL) { parentButton = parentButton->next; }
parentButton->next = button;
}
button->label = calloc(strlen(label), sizeof(char) + 1);
strcpy(button->label, label);
button->on_click = on_click;
button->clickSound = clickSound;
struct Object* obj = spawn_object_rel_with_rot(parent->me->object, MODEL_MAIN_MENU_MARIO_NEW_BUTTON, bhvMenuButton, x * -1, y, -1, 0, 0x8000, 0);
obj->oMenuButtonScale = scale;
obj->oFaceAngleRoll = 0;
obj->oMenuButtonTimer = 0;
obj->oMenuButtonOrigPosX = obj->oParentRelativePosX;
obj->oMenuButtonOrigPosY = obj->oParentRelativePosY;
obj->oMenuButtonOrigPosZ = obj->oParentRelativePosZ;
obj->oMenuButtonIsCustom = 1;
obj->oMenuButtonState = MENU_BUTTON_STATE_DEFAULT;
button->object = obj;
return button;
}
struct CustomMenu* custom_menu_create(struct CustomMenu* parent, char* label, u16 x, u16 y, f32 scale) {
struct CustomMenuButton* button = custom_menu_create_button(parent, label, x, y, scale, SOUND_MENU_CAMERA_ZOOM_IN, NULL);
struct CustomMenu* menu = calloc(1, sizeof(struct CustomMenu));
menu->parent = parent;
menu->depth = parent->depth + 1;
menu->headerY = 25;
menu->me = button;
button->menu = menu;
return menu;
}
void custom_menu_system_init(void) {
// allocate the main menu and set it to current
sHead = calloc(1, sizeof(struct CustomMenu));
sHead->me = calloc(1, sizeof(struct CustomMenuButton));
sCurrentMenu = sHead;
// spawn the main menu game object
struct Object* obj = spawn_object_rel_with_rot(gCurrentObject, MODEL_MAIN_MENU_GREEN_SCORE_BUTTON, bhvMenuButton, 0, 0, 0, 0, 0, 0);
obj->oParentRelativePosZ += 1000;
obj->oMenuButtonState = MENU_BUTTON_STATE_FULLSCREEN;
obj->oFaceAngleYaw = 0x8000;
obj->oFaceAngleRoll = 0;
obj->oMenuButtonScale = 9.0f;
obj->oMenuButtonOrigPosZ = obj->oPosZ;
obj->oMenuButtonOrigPosX = 99999;
obj->oMenuButtonIsCustom = 1;
sHead->me->object = obj;
custom_menu_init(sHead);
}
void custom_menu_destroy(void) {
// TODO: clean up all of the calloc()'d memory
}
void custom_menu_system_loop(void) {
custom_menu_loop();
}
static void button_force_instant_close(struct Object* obj) {
obj->oFaceAngleYaw = 0x8000;
obj->oFaceAnglePitch = 0;
obj->oParentRelativePosX = obj->oMenuButtonOrigPosX;
obj->oParentRelativePosY = obj->oMenuButtonOrigPosY;
obj->oParentRelativePosZ = obj->oMenuButtonOrigPosZ;
obj->oMenuButtonScale = 0.11111111f;
obj->oMenuButtonState = MENU_BUTTON_STATE_DEFAULT;
obj->oMenuButtonTimer = 0;
}
static void button_force_instant_open(struct Object* obj) {
obj->oFaceAngleYaw = 0;
obj->oFaceAnglePitch = 0;
obj->oParentRelativePosX = 0.0f;
obj->oParentRelativePosY = 0.0f;
obj->oParentRelativePosZ = -801;
obj->oMenuButtonScale = 0.623111;
obj->oMenuButtonState = MENU_BUTTON_STATE_FULLSCREEN;
obj->oMenuButtonTimer = 0;
}
void custom_menu_open(struct CustomMenu* menu) {
if (sCurrentMenu == menu) { return; }
if (menu == NULL) { return; }
// force instant-close all parents if not a direct route
{
// check all buttons of current menu to see if the desired menu is directly beneath it
struct CustomMenuButton* onButton = sCurrentMenu->buttons;
u8 foundMenu = FALSE;
while (onButton != NULL) {
if (onButton == menu->me) { foundMenu = TRUE; break; }
onButton = onButton->next;
}
// if not direct route, force close all the way to the main menu
if (!foundMenu) {
struct CustomMenu* onMenu = sCurrentMenu;
while (onMenu != NULL && onMenu != sHead) {
struct Object* obj = onMenu->me->object;
if (obj->oMenuButtonState != MENU_BUTTON_STATE_FULLSCREEN) { break; }
button_force_instant_close(obj);
if (onMenu->on_close != NULL) { onMenu->on_close(); }
onMenu = onMenu->parent;
}
}
}
// force instant-open all parents
{
struct CustomMenu* onMenu = menu->parent;
while (onMenu != NULL) {
struct Object* obj = onMenu->me->object;
if (obj->oMenuButtonState == MENU_BUTTON_STATE_FULLSCREEN) { break; }
button_force_instant_open(obj);
onMenu = onMenu->parent;
}
}
struct Object* obj = menu->me->object;
obj->oMenuButtonState = MENU_BUTTON_STATE_GROWING;
obj->oMenuButtonTimer = 0;
gMenuStringAlpha = 0;
sLastMenu = sCurrentMenu;
sCurrentMenu = menu;
}
void custom_menu_close(void) {
struct Object* obj = sCurrentMenu->me->object;
obj->oMenuButtonState = MENU_BUTTON_STATE_SHRINKING;
obj->oMenuButtonTimer = 0;
gMenuStringAlpha = 0;
if (sCurrentMenu->on_close != NULL) { sCurrentMenu->on_close(); }
sLastMenu = sCurrentMenu;
if (sCurrentMenu->parent != NULL) {
sCurrentMenu = sCurrentMenu->parent;
}
}
void custom_menu_close_system(void) {
sHead->me->object->oMenuButtonState = MENU_BUTTON_STATE_SHRINKING;
gInCustomMenu = FALSE;
}
static s32 cursor_inside_button(struct CustomMenuButton* button, f32 cursorX, f32 cursorY) {
f32 x = button->object->oParentRelativePosX;
f32 y = button->object->oParentRelativePosY;
f32 scale = button->object->oMenuButtonScale;
x *= -0.137f;
y *= 0.137f;
s16 maxX = x + scale * 185.0f;
s16 minX = x - scale * 185.0f;
s16 maxY = y + scale * 185.0f;
s16 minY = y - scale * 101.0f;
return (cursorX < maxX && minX < cursorX && cursorY < maxY && minY < cursorY);
}
void custom_menu_cursor_click(f32 cursorX, f32 cursorY) {
#ifdef VERSION_EU
u16 cursorClickButtons = (A_BUTTON | B_BUTTON | START_BUTTON | Z_TRIG);
#else
u16 cursorClickButtons = (A_BUTTON | B_BUTTON | START_BUTTON);
#endif
if (!(gPlayer3Controller->buttonPressed & cursorClickButtons)) { return; }
if (sCurrentMenu->me->object->oMenuButtonState != MENU_BUTTON_STATE_FULLSCREEN) { return; }
if (sErrorDialog != NULL) {
struct ErrorDialog* current = sErrorDialog;
sErrorDialog = sErrorDialog->next;
free(current->dialog);
free(current);
play_sound(SOUND_ACTION_BONK, gDefaultSoundArgs);
if (sErrorDialog != NULL) {
play_sound(SOUND_MARIO_OOOF2, gDefaultSoundArgs);
}
return;
}
struct CustomMenuButton* button = sCurrentMenu->buttons;
while (button != NULL) {
if (cursor_inside_button(button, cursorX, cursorY)) {
u8 didSomething = FALSE;
if (button->menu != NULL) {
custom_menu_open(button->menu);
didSomething = TRUE;
}
if (button->on_click != NULL) {
button->on_click();
didSomething = TRUE;
}
if (button->clickSound != 0) {
play_sound(button->clickSound, gDefaultSoundArgs);
}
if (didSomething) { break; }
}
button = button->next;
}
}
static void button_label_pos(struct CustomMenuButton* button, s16* outX, s16* outY) {
f32 x = button->object->oParentRelativePosX;
f32 y = button->object->oParentRelativePosY;
x -= strlen(button->label) * -27.0f;
y += -163.0f;
*outX = 165.0f + x * -0.137f;
*outY = 110.0f + y * 0.137f;
}
void custom_menu_print_strings(void) {
// figure out alpha
struct Object* curObj = sCurrentMenu->me->object;
struct Object* lastObj = (sLastMenu != NULL) ? sLastMenu->me->object : NULL;
if (curObj != NULL && lastObj != NULL) {
if (curObj->oMenuButtonState == MENU_BUTTON_STATE_FULLSCREEN && lastObj->oMenuButtonState != MENU_BUTTON_STATE_SHRINKING) {
if (gMenuStringAlpha < 250) {
gMenuStringAlpha += 10;
} else {
gMenuStringAlpha = 255;
}
}
}
// print header
gSPDisplayList(gDisplayListHead++, dl_rgba16_text_begin);
gDPSetEnvColor(gDisplayListHead++, 255, 255, 255, gMenuStringAlpha);
char* headerLabel = sCurrentMenu->me->label;
u16 headerLabelLen = strlen(headerLabel);
u16 headerX = (u16)(159.66f - (headerLabelLen * 5.66f));
unsigned char header[64];
str_ascii_to_dialog(headerLabel, header, headerLabelLen);
print_hud_lut_string(HUD_LUT_DIFF, headerX, sCurrentMenu->headerY, header);
gSPDisplayList(gDisplayListHead++, dl_rgba16_text_end);
// print text
gSPDisplayList(gDisplayListHead++, dl_ia_text_begin);
struct CustomMenuButton* button = sCurrentMenu->buttons;
while (button != NULL) {
gDPSetEnvColor(gDisplayListHead++, 222, 222, 222, gMenuStringAlpha);
s16 x, y;
button_label_pos(button, &x, &y);
print_generic_ascii_string(x, y, button->label);
button = button->next;
}
if (sCurrentMenu->draw_strings != NULL) { sCurrentMenu->draw_strings(); }
gSPDisplayList(gDisplayListHead++, dl_ia_text_end);
}
void custom_menu_render_top(void) {
// print error message
if (sErrorDialog != NULL) {
// black screen
create_dl_translation_matrix(MENU_MTX_PUSH, GFX_DIMENSIONS_FROM_LEFT_EDGE(0), 240.0f, 0);
create_dl_scale_matrix(MENU_MTX_NOPUSH, GFX_DIMENSIONS_ASPECT_RATIO * SCREEN_HEIGHT / 130.0f, 3.0f, 1.0f);
gDPSetEnvColor(gDisplayListHead++, 0, 0, 0, 240);
gSPDisplayList(gDisplayListHead++, dl_draw_text_bg_box);
gSPPopMatrix(gDisplayListHead++, G_MTX_MODELVIEW);
// print text
gSPDisplayList(gDisplayListHead++, dl_ia_text_begin);
f32 textWidth = get_generic_dialog_width(sErrorDialog->dialog);
f32 textHeight = get_generic_dialog_height(sErrorDialog->dialog);
f32 xPos = (SCREEN_WIDTH - textWidth) / 2.0f;
f32 yPos = (SCREEN_HEIGHT + textHeight) / 2.0f;
gDPSetEnvColor(gDisplayListHead++, 30, 30, 30, 255);
print_generic_string(xPos, yPos, sErrorDialog->dialog);
gDPSetEnvColor(gDisplayListHead++, 255, 255, 255, 255);
print_generic_string((xPos - 1), (yPos + 1), sErrorDialog->dialog);
gSPDisplayList(gDisplayListHead++, dl_ia_text_end);
}
}
/**
* Grow from submenu, used by selecting a file in the score menu.
*/
void bhv_menu_button_growing_from_custom(struct Object* button) {
if (button->oMenuButtonTimer < 16) {
button->oFaceAngleYaw += 0x800;
}
if (button->oMenuButtonTimer < 8) {
button->oFaceAnglePitch += 0x800;
}
if (button->oMenuButtonTimer >= 8 && button->oMenuButtonTimer < 16) {
button->oFaceAnglePitch -= 0x800;
}
button->oParentRelativePosX -= button->oMenuButtonOrigPosX / 16.0;
button->oParentRelativePosY -= button->oMenuButtonOrigPosY / 16.0;
button->oParentRelativePosZ -= 50;
button->oMenuButtonScale += 0.032f;
button->oMenuButtonTimer++;
if (button->oMenuButtonTimer == 16) {
button->oParentRelativePosX = 0.0f;
button->oParentRelativePosY = 0.0f;
button->oMenuButtonState = MENU_BUTTON_STATE_FULLSCREEN;
button->oMenuButtonTimer = 0;
}
}
/**
* Shrink back to submenu, used to return back while inside a score save menu.
*/
void bhv_menu_button_shrinking_to_custom(struct Object* button) {
if (button->oMenuButtonTimer < 16) {
button->oFaceAngleYaw -= 0x800;
}
if (button->oMenuButtonTimer < 8) {
button->oFaceAnglePitch -= 0x800;
}
if (button->oMenuButtonTimer >= 8 && button->oMenuButtonTimer < 16) {
button->oFaceAnglePitch += 0x800;
}
button->oParentRelativePosX += button->oMenuButtonOrigPosX / 16.0;
button->oParentRelativePosY += button->oMenuButtonOrigPosY / 16.0;
button->oParentRelativePosZ += 50;
button->oMenuButtonScale -= 0.032f;
button->oMenuButtonTimer++;
if (button->oMenuButtonTimer == 16) {
button->oParentRelativePosX = button->oMenuButtonOrigPosX;
button->oParentRelativePosY = button->oMenuButtonOrigPosY;
button->oMenuButtonScale = 0.11111111f;
button->oMenuButtonState = MENU_BUTTON_STATE_DEFAULT;
button->oMenuButtonTimer = 0;
}
}
void custom_menu_error(char* message) {
struct ErrorDialog* errorDialog = malloc(sizeof(struct ErrorDialog));
memset(errorDialog, 0, sizeof(struct ErrorDialog));
errorDialog->dialog = malloc(sizeof(u8) * (strlen(message) + 1));
str_ascii_to_dialog(message, errorDialog->dialog, strlen(message));
if (sErrorDialog == NULL) {
sErrorDialog = errorDialog;
play_sound(SOUND_MARIO_OOOF2, gDefaultSoundArgs);
} else {
struct ErrorDialog* item = sErrorDialog;
while (item != NULL) {
if (item->next == NULL) {
item->next = errorDialog;
break;
}
item = item->next;
}
}
}

View file

@ -1,51 +0,0 @@
#ifndef CUSTOM_MENU_SYSTEM_H
#define CUSTOM_MENU_SYSTEM_H
#include "file_select.h"
struct CustomMenuButton {
struct Object* object;
char* label;
void (*on_click)(void);
u32 clickSound;
struct CustomMenu* menu;
struct CustomMenuButton* next;
};
struct CustomMenu {
struct CustomMenu* parent;
struct CustomMenuButton* me;
struct CustomMenuButton* buttons;
u16 headerY;
u16 depth;
void (*draw_strings)(void);
void (*on_close)(void);
};
struct CustomMenuButtonScale {
f32 small;
f32 medium;
f32 large;
};
extern struct CustomMenuButtonScale gButtonScale;
extern u8 gMenuStringAlpha;
void custom_menu_system_init(void);
struct CustomMenu* custom_menu_create(struct CustomMenu* parent, char* label, u16 x, u16 y, f32 scale);
struct CustomMenuButton* custom_menu_create_button(struct CustomMenu* parent, char* label, u16 x, u16 y, f32 scale, s32 clickSound, void (*on_click)(void));
void custom_menu_system_loop(void);
void custom_menu_print_strings(void);
void custom_menu_render_top(void);
void custom_menu_cursor_click(f32 x, f32 y);
void custom_menu_open(struct CustomMenu* menu);
void custom_menu_close(void);
void custom_menu_close_system(void);
void bhv_menu_button_growing_from_custom(struct Object* button);
void bhv_menu_button_shrinking_to_custom(struct Object* button);
void custom_menu_error(char* message);
#endif // CUSTOM_MENU_SYSTEM_H

View file

@ -23,9 +23,6 @@
#include "eu_translation.h"
#include "custom_menu_system.h"
#include "custom_menu.h"
#ifdef VERSION_EU
#undef LANGUAGE_FUNCTION
#define LANGUAGE_FUNCTION sLanguageMode
@ -38,9 +35,6 @@
* special menu messages and phases, button states and button clicked checks.
*/
u8 gInCustomMenu = 1;
u8 sIgnoreMenuTimer = 5;
#ifdef VERSION_US
// The current sound mode is automatically centered on US due to
// the large length difference between options.
@ -530,9 +524,7 @@ void bhv_menu_button_loop(void) {
gCurrentObject->oMenuButtonOrigPosZ = gCurrentObject->oPosZ;
break;
case MENU_BUTTON_STATE_GROWING: // Switching from button to menu state
if (gInCustomMenu) {
bhv_menu_button_growing_from_custom(gCurrentObject);
} else if (sCurrentMenuLevel == MENU_LAYER_MAIN) {
if (sCurrentMenuLevel == MENU_LAYER_MAIN) {
bhv_menu_button_growing_from_main_menu(gCurrentObject);
} else if (sCurrentMenuLevel == MENU_LAYER_SUBMENU) {
bhv_menu_button_growing_from_submenu(gCurrentObject); // Only used for score files
@ -543,9 +535,7 @@ void bhv_menu_button_loop(void) {
case MENU_BUTTON_STATE_FULLSCREEN: // Menu state
break;
case MENU_BUTTON_STATE_SHRINKING: // Switching from menu to button state
if (gInCustomMenu) {
bhv_menu_button_shrinking_to_custom(gCurrentObject);
} else if (sCurrentMenuLevel == MENU_LAYER_MAIN) {
if (sCurrentMenuLevel == MENU_LAYER_MAIN) {
bhv_menu_button_shrinking_to_main_menu(gCurrentObject);
} else if (sCurrentMenuLevel == MENU_LAYER_SUBMENU) {
bhv_menu_button_shrinking_to_submenu(gCurrentObject); // Only used for score files
@ -1127,7 +1117,6 @@ void check_sound_mode_menu_clicked_buttons(struct Object *soundModeButton) {
void load_main_menu_save_file(struct Object *fileButton, s32 fileNum) {
if (fileButton->oMenuButtonState == MENU_BUTTON_STATE_FULLSCREEN) {
sSelectedFileNum = fileNum;
custom_menu_on_load_save_file(sSelectedFileNum);
}
}
@ -1362,9 +1351,6 @@ void bhv_menu_button_manager_init(void) {
sMainMenuButtons[MENU_BUTTON_SOUND_MODE]->oMenuButtonScale = 1.0f;
sTextBaseAlpha = 0;
// custom menus
custom_menu_system_init();
}
#if defined(VERSION_JP) || defined(VERSION_SH)
@ -1378,10 +1364,6 @@ void bhv_menu_button_manager_init(void) {
* Also play a sound and/or render buttons depending of the button ID selected.
*/
void check_main_menu_clicked_buttons(void) {
if (sIgnoreMenuTimer > 0) {
sIgnoreMenuTimer--;
return;
}
#ifdef VERSION_EU
if (sMainMenuTimer >= 5) {
#endif
@ -1461,10 +1443,6 @@ void check_main_menu_clicked_buttons(void) {
* is loaded, and that checks what buttonID is clicked in the main menu.
*/
void bhv_menu_button_manager_loop(void) {
if (gInCustomMenu) {
custom_menu_system_loop();
return;
}
switch (sSelectedButtonID) {
case MENU_BUTTON_NONE:
check_main_menu_clicked_buttons();
@ -1651,13 +1629,6 @@ void handle_controller_cursor_input(void) {
if (sCursorPos[1] < -90.0f) {
sCursorPos[1] = -90.0f;
}
if (sCursorClickingTimer == 0) {
handle_cursor_button_input();
if (gInCustomMenu) {
custom_menu_cursor_click(sCursorPos[0], sCursorPos[1]);
}
}
}
/**
@ -2741,11 +2712,6 @@ static void print_file_select_strings(void) {
create_dl_ortho_matrix();
if (gInCustomMenu) {
custom_menu_print_strings();
return;
}
switch (sSelectedButtonID) {
case MENU_BUTTON_NONE:
#ifdef VERSION_EU
@ -2804,7 +2770,6 @@ Gfx *geo_file_select_strings_and_menu_cursor(s32 callContext, UNUSED struct Grap
if (callContext == GEO_CONTEXT_RENDER) {
print_file_select_strings();
print_menu_cursor();
custom_menu_render_top();
}
return NULL;
}

View file

@ -129,7 +129,6 @@ enum SoundModeMenuActionPhase {
extern f32 sCursorPos[2];
extern s8 sSelectedFileNum;
extern u8 gInCustomMenu;
void beh_yellow_background_menu_init(void);
void beh_yellow_background_menu_loop(void);

View file

@ -92,7 +92,8 @@ bool configCameraAnalog = true;
bool configCameraMouse = false;
#endif
bool configSkipIntro = 0;
bool configShareLives = 0;
bool configShareLives = 0;
bool configEnableCheats = 0;
bool configHUD = true;
#ifdef DISCORDRPC
bool configDiscordRPC = true;
@ -104,9 +105,8 @@ unsigned int configHostPort = DEFAULT_PORT;
unsigned int configHostSaveSlot = 1;
unsigned int configPlayerInteraction = 1;
unsigned int configPlayerKnockbackStrength = 25;
unsigned int configStayInLevelAfterStar = 0;
bool configStayInLevelAfterStar = 0;
unsigned int configNetworkSystem = 0;
bool configLuigiSounds = true;
static const struct ConfigOption options[] = {
{.name = "fullscreen", .type = CONFIG_TYPE_BOOL, .boolValue = &configWindow.fullscreen},
@ -154,6 +154,7 @@ static const struct ConfigOption options[] = {
#endif
{.name = "skip_intro", .type = CONFIG_TYPE_BOOL, .boolValue = &configSkipIntro},
{.name = "share_lives", .type = CONFIG_TYPE_BOOL, .boolValue = &configShareLives},
{.name = "enable_cheats", .type = CONFIG_TYPE_BOOL, .boolValue = &configEnableCheats},
#ifdef DISCORDRPC
{.name = "discordrpc_enable", .type = CONFIG_TYPE_BOOL, .boolValue = &configDiscordRPC},
#endif
@ -164,9 +165,8 @@ static const struct ConfigOption options[] = {
{.name = "coop_host_save_slot", .type = CONFIG_TYPE_UINT , .uintValue = &configHostSaveSlot},
{.name = "coop_player_interaction", .type = CONFIG_TYPE_UINT , .uintValue = &configPlayerInteraction},
{.name = "coop_player_knockback_strength", .type = CONFIG_TYPE_UINT , .uintValue = &configPlayerKnockbackStrength},
{.name = "coop_stay_in_level_after_star", .type = CONFIG_TYPE_UINT , .uintValue = &configStayInLevelAfterStar},
{.name = "coop_stay_in_level_after_star", .type = CONFIG_TYPE_UINT , .boolValue = &configStayInLevelAfterStar},
{.name = "coop_network_system", .type = CONFIG_TYPE_UINT , .uintValue = &configNetworkSystem},
{.name = "coop_luigi_sounds", .type = CONFIG_TYPE_BOOL , .boolValue = &configLuigiSounds},
};
// Reads an entire line from a file (excluding the newline character) and returns an allocated string

View file

@ -61,6 +61,7 @@ extern bool configCameraAnalog;
extern bool configHUD;
extern bool configSkipIntro;
extern bool configShareLives;
extern bool configEnableCheats;
#ifdef DISCORDRPC
extern bool configDiscordRPC;
#endif
@ -70,9 +71,8 @@ extern unsigned int configHostPort;
extern unsigned int configHostSaveSlot;
extern unsigned int configPlayerInteraction;
extern unsigned int configPlayerKnockbackStrength;
extern unsigned int configStayInLevelAfterStar;
extern bool configStayInLevelAfterStar;
extern unsigned int configNetworkSystem;
extern bool configLuigiSounds;
void configfile_load(const char *filename);
void configfile_save(const char *filename);

View file

@ -17,20 +17,7 @@
#include "pc/pc_main.h"
#include "engine/math_util.h"
#include "menu/file_select.h"
#include "game/chat.h"
// TODO: use some common lookup header
#define SCANCODE_BACKSPACE 0x0E
#define SCANCODE_ESCAPE 0x01
#define SCANCODE_ENTER 0x1C
#define SCANCODE_V 0x2F
#define SCANCODE_INSERT 0x152
#define SCANCODE_CTRL1 0x1D
#define SCANCODE_CTRL2 0x11D
#define SCANCODE_SHIFT1 0x2A
#define SCANCODE_SHIFT2 0x36
#define SCANCODE_ALT1 0x38
#define SCANCODE_ALT2 0x138
#include "src/pc/djui/djui.h"
static int keyboard_buttons_down;
@ -40,16 +27,6 @@ static int num_keybinds = 0;
static u32 keyboard_lastkey = VK_INVALID;
char gTextInput[MAX_TEXT_INPUT];
static u8 sInTextInput = false;
static u8 sMaxTextInput = 0;
static clock_t sIgnoreTextInput = 0;
u8 held_ctrl, held_shift, held_alt;
static enum TextInputMode sTextInputMode;
void (*textInputOnEscape)(void) = NULL;
void (*textInputOnEnter)(void) = NULL;
static int keyboard_map_scancode(int scancode) {
int ret = 0;
for (int i = 0; i < num_keybinds; i++) {
@ -60,68 +37,16 @@ static int keyboard_map_scancode(int scancode) {
return ret;
}
static void keyboard_alter_modifier(int scancode, bool down) {
if (down) {
switch (scancode) {
case SCANCODE_CTRL1: held_ctrl |= (1 << 0); break;
case SCANCODE_CTRL2: held_ctrl |= (1 << 1); break;
case SCANCODE_SHIFT1: held_shift |= (1 << 0); break;
case SCANCODE_SHIFT2: held_shift |= (1 << 1); break;
case SCANCODE_ALT1: held_alt |= (1 << 0); break;
case SCANCODE_ALT2: held_alt |= (1 << 1); break;
}
} else {
switch (scancode) {
case SCANCODE_CTRL1: held_ctrl &= ~(1 << 0); break;
case SCANCODE_CTRL2: held_ctrl &= ~(1 << 1); break;
case SCANCODE_SHIFT1: held_shift &= ~(1 << 0); break;
case SCANCODE_SHIFT2: held_shift &= ~(1 << 1); break;
case SCANCODE_ALT1: held_alt &= ~(1 << 0); break;
case SCANCODE_ALT2: held_alt &= ~(1 << 1); break;
}
}
}
bool keyboard_on_key_down(int scancode) {
// alter the held value of modifier keys
keyboard_alter_modifier(scancode, true);
#ifdef DEBUG
if (!sInTextInput) {
debug_keyboard_on_key_down(scancode);
}
debug_keyboard_on_key_down(scancode);
#endif
if (sInTextInput) {
// perform text-input-specific actions
switch (scancode & 0xFF) {
case SCANCODE_BACKSPACE:
gTextInput[max(strlen(gTextInput) - 1, 0)] = '\0';
break;
case SCANCODE_ESCAPE:
if (textInputOnEscape != NULL) { textInputOnEscape(); }
break;
case SCANCODE_ENTER:
if (textInputOnEnter != NULL) { textInputOnEnter(); }
break;
case SCANCODE_V:
if (held_ctrl) { keyboard_on_text_input(wm_api->get_clipboard_text()); }
break;
case SCANCODE_INSERT:
if (held_shift) { keyboard_on_text_input(wm_api->get_clipboard_text()); }
break;
}
// ignore any normal key down event if we're in text-input mode
// see if interactable captures this scancode
if (djui_interactable_on_key_down(scancode)) {
return FALSE;
}
if (!held_alt && (scancode == (int)configKeyChat[0])) {
if (sSelectedFileNum != 0) {
sIgnoreTextInput = clock() + CLOCKS_PER_SEC * 0.01f;
chat_start_input();
}
}
int mapped = keyboard_map_scancode(scancode);
keyboard_buttons_down |= mapped;
keyboard_lastkey = scancode;
@ -129,13 +54,7 @@ bool keyboard_on_key_down(int scancode) {
}
bool keyboard_on_key_up(int scancode) {
// alter the held value of modifier keys
keyboard_alter_modifier(scancode, false);
if (sInTextInput) {
// ignore any key up event if we're in text-input mode
return FALSE;
}
djui_interactable_on_key_up(scancode);
int mapped = keyboard_map_scancode(scancode);
keyboard_buttons_down &= ~mapped;
@ -148,87 +67,8 @@ void keyboard_on_all_keys_up(void) {
keyboard_buttons_down = 0;
}
char* keyboard_start_text_input(enum TextInputMode inInputMode, u8 inMaxTextInput, void (*onEscape)(void), void (*onEnter)(void)) {
// set text-input events
textInputOnEscape = onEscape;
textInputOnEnter = onEnter;
sMaxTextInput = inMaxTextInput;
// clear buffer
for (int i = 0; i < MAX_TEXT_INPUT; i++) { gTextInput[i] = '\0'; }
// clear held-value for modifiers
held_ctrl = 0;
held_shift = 0;
held_alt = 0;
// start allowing text input
wm_api->start_text_input();
sTextInputMode = inInputMode;
sInTextInput = true;
}
void keyboard_stop_text_input(void) {
// stop allowing text input
sInTextInput = false;
wm_api->stop_text_input();
}
bool keyboard_in_text_input(void) { return sInTextInput; }
static bool keyboard_allow_character_input(char c) {
switch (sTextInputMode) {
case TIM_IP:
// IP only allows numbers, periods, and spaces
return (c >= '0' && c <= '9')
|| (c == '.')
|| (c == ' ');
case TIM_MULTI_LINE:
// multi-line allows new-line character
if (c == '\n') { return true; }
// intentional fall-through
case TIM_SINGLE_LINE:
// allow all characters that we can display in-game
return (c >= '0' && c <= '9')
|| (c >= 'a' && c <= 'z')
|| (c >= 'A' && c <= 'Z')
|| (c == '\'') || (c == '.')
|| (c == ',') || (c == '-')
|| (c == '(') || (c == ')')
|| (c == '&') || (c == '!')
|| (c == '%') || (c == '?')
|| (c == '"') || (c == '~')
|| (c == '*') || (c == ' ');
}
return false;
}
void keyboard_on_text_input(char* text) {
if (sIgnoreTextInput != 0 && clock() <= sIgnoreTextInput) {
sIgnoreTextInput = 0;
return;
}
if (!sInTextInput) { return; }
// sanity check input
if (text == NULL) { return; }
int i = strlen(gTextInput);
while (*text != '\0') {
// make sure we don't overrun the buffer
if (i >= MAX_TEXT_INPUT) { break; }
if (i >= sMaxTextInput) { break; }
// copy over character if we're allowed to input it
if (keyboard_allow_character_input(*text)) {
gTextInput[i++] = *text;
}
text++;
}
djui_interactable_on_text_input(text);
}
static void keyboard_add_binds(int mask, unsigned int *scancode) {

View file

@ -6,26 +6,32 @@
# define VK_BASE_KEYBOARD 0x0000
#define SCANCODE_ESCAPE 1
#define SCANCODE_BACKSPACE 14
#define SCANCODE_ENTER 28
#define SCANCODE_CONTROL_LEFT 29
#define SCANCODE_SHIFT_LEFT 42
#define SCANCODE_A 30
#define SCANCODE_X 45
#define SCANCODE_C 46
#define SCANCODE_V 47
#define SCANCODE_SHIFT_RIGHT 54
#define SCANCODE_CONTROL_RIGHT 285
#define SCANCODE_HOME 327
#define SCANCODE_LEFT 331
#define SCANCODE_RIGHT 333
#define SCANCODE_END 335
#define SCANCODE_INSERT 338
#define SCANCODE_DELETE 339
#ifdef __cplusplus
extern "C" {
#endif
#define MAX_TEXT_INPUT 255
extern char gTextInput[];
enum TextInputMode {
TIM_IP,
TIM_MULTI_LINE,
TIM_SINGLE_LINE,
};
bool keyboard_on_key_down(int scancode);
bool keyboard_on_key_up(int scancode);
void keyboard_on_all_keys_up(void);
void keyboard_on_text_input(char* text);
char* keyboard_start_text_input(enum TextInputMode, u8 inMaxTextInput, void (*onEscape)(void), void (*onEnter)(void));
void keyboard_stop_text_input(void);
bool keyboard_in_text_input(void);
#ifdef __cplusplus
}

View file

@ -6,6 +6,11 @@
extern int mouse_x;
extern int mouse_y;
extern int mouse_window_buttons;
extern int mouse_window_x;
extern int mouse_window_y;
#define VK_BASE_MOUSE 0x2000
extern struct ControllerAPI controller_mouse;

View file

@ -7,4 +7,6 @@
extern struct ControllerAPI controller_sdl;
void controller_sdl_read_mouse_window(void);
#endif

View file

@ -41,6 +41,10 @@ enum {
int mouse_x;
int mouse_y;
int mouse_window_buttons;
int mouse_window_x;
int mouse_window_y;
#ifdef BETTERCAMERA
extern u8 newcam_mouse;
#endif
@ -155,9 +159,11 @@ static void controller_sdl_read(OSContPad *pad) {
u32 mouse = SDL_GetRelativeMouseState(&mouse_x, &mouse_y);
for (u32 i = 0; i < num_mouse_binds; ++i)
if (mouse & SDL_BUTTON(mouse_binds[i][0]))
pad->button |= mouse_binds[i][1];
if (!gInteractableOverridePad) {
for (u32 i = 0; i < num_mouse_binds; ++i)
if (mouse & SDL_BUTTON(mouse_binds[i][0]))
pad->button |= mouse_binds[i][1];
}
// remember buttons that changed from 0 to 1
last_mouse = (mouse_buttons ^ mouse) & mouse;
@ -238,6 +244,11 @@ static void controller_sdl_read(OSContPad *pad) {
}
}
void controller_sdl_read_mouse_window(void) {
if (!init_ok) { return; }
mouse_window_buttons = SDL_GetMouseState(&mouse_window_x, &mouse_window_y);
}
static void controller_sdl_rumble_play(f32 strength, f32 length) { }
static void controller_sdl_rumble_stop(void) { }

View file

@ -20,6 +20,8 @@
#include "game/level_update.h"
#include "pc/djui/djui.h"
// mouse buttons are also in the controller namespace (why), just offset 0x100
#define VK_OFS_SDL_MOUSE 0x0100
#define VK_BASE_SDL_MOUSE (VK_BASE_SDL_GAMEPAD + VK_OFS_SDL_MOUSE)
@ -31,6 +33,10 @@
int mouse_x;
int mouse_y;
int mouse_window_buttons;
int mouse_window_x;
int mouse_window_y;
#ifdef BETTERCAMERA
extern u8 newcam_mouse;
#endif
@ -156,13 +162,14 @@ static void controller_sdl_read(OSContPad *pad) {
SDL_SetRelativeMouseMode(SDL_TRUE);
else
SDL_SetRelativeMouseMode(SDL_FALSE);
u32 mouse = SDL_GetRelativeMouseState(&mouse_x, &mouse_y);
for (u32 i = 0; i < num_mouse_binds; ++i)
if (mouse & SDL_BUTTON(mouse_binds[i][0]))
pad->button |= mouse_binds[i][1];
if (!gInteractableOverridePad) {
for (u32 i = 0; i < num_mouse_binds; ++i)
if (mouse & SDL_BUTTON(mouse_binds[i][0]))
pad->button |= mouse_binds[i][1];
}
// remember buttons that changed from 0 to 1
last_mouse = (mouse_buttons ^ mouse) & mouse;
mouse_buttons = mouse;
@ -262,6 +269,11 @@ static void controller_sdl_read(OSContPad *pad) {
}
}
void controller_sdl_read_mouse_window(void) {
if (!init_ok) { return; }
mouse_window_buttons = SDL_GetMouseState(&mouse_window_x, &mouse_window_y);
}
static void controller_sdl_rumble_play(f32 strength, f32 length) {
if (sdl_haptic)
SDL_HapticRumblePlay(sdl_haptic, strength, (u32)(length * 1000.0f));

55
src/pc/djui/djui.c Normal file
View file

@ -0,0 +1,55 @@
#include "djui.h"
#include "../debuglog.h"
#include "pc/cliopts.h"
static Gfx* sSavedDisplayListHead = NULL;
struct DjuiRoot* gDjuiRoot = NULL;
struct DjuiText* gDjuiPauseOptions = NULL;
void djui_init(void) {
gDjuiRoot = djui_root_create();
gDjuiPauseOptions = djui_text_create(&gDjuiRoot->base, "R Button - Options");
djui_base_set_size_type(&gDjuiPauseOptions->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
djui_base_set_size(&gDjuiPauseOptions->base, 1.0f, 32);
djui_base_set_location(&gDjuiPauseOptions->base, 0, 16);
djui_text_set_drop_shadow(gDjuiPauseOptions, 0, 0, 0, 255);
djui_text_set_alignment(gDjuiPauseOptions, DJUI_HALIGN_CENTER, DJUI_VALIGN_CENTER);
djui_base_set_visible(&gDjuiPauseOptions->base, false);
if (gCLIOpts.Network != NT_SERVER) {
djui_panel_main_create(NULL);
//djui_panel_debug_create();
}
djui_cursor_create();
}
void djui_connect_menu_open(void) {
djui_panel_shutdown();
djui_panel_main_create(NULL);
djui_panel_join_create(NULL);
djui_panel_join_message_create(NULL);
}
void djui_render_patch(void) {
// reset the head and re-render DJUI
if (sSavedDisplayListHead == NULL) { return; }
gDisplayListHead = sSavedDisplayListHead;
djui_render();
gDPFullSync(gDisplayListHead++);
gSPEndDisplayList(gDisplayListHead++);
}
void djui_render(void) {
sSavedDisplayListHead = gDisplayListHead;
create_dl_ortho_matrix();
djui_panel_update();
djui_popup_update();
djui_base_render(&gDjuiRoot->base);
djui_cursor_update();
djui_interactable_update();
}

58
src/pc/djui/djui.h Normal file
View file

@ -0,0 +1,58 @@
#pragma once
#include <PR/gbi.h>
#include <PR/ultratypes.h>
#include <stdint.h>
#include <stdbool.h>
#include <stdlib.h>
#include "game/game_init.h"
#include "game/ingame_menu.h"
#include "djui_types.h"
#include "djui_font.h"
#include "djui_gfx.h"
#include "djui_base.h"
#include "djui_interactable.h"
#include "djui_root.h"
#include "djui_cursor.h"
#include "djui_rect.h"
#include "djui_text.h"
#include "djui_image.h"
#include "djui_three_panel.h"
#include "djui_button.h"
#include "djui_inputbox.h"
#include "djui_slider.h"
#include "djui_checkbox.h"
#include "djui_flow_layout.h"
#include "djui_selectionbox.h"
#include "djui_bind.h"
#include "djui_popup.h"
#include "djui_chat_box.h"
#include "djui_chat_message.h"
#include "djui_panel.h"
#include "djui_panel_menu.h"
#include "djui_panel_debug.h"
#include "djui_panel_main.h"
#include "djui_panel_host.h"
#include "djui_panel_host_save.h"
#include "djui_panel_host_message.h"
#include "djui_panel_join.h"
#include "djui_panel_join_message.h"
#include "djui_panel_pause.h"
#include "djui_panel_options.h"
#include "djui_panel_camera.h"
#include "djui_panel_controls.h"
#include "djui_panel_display.h"
#include "djui_panel_sound.h"
#include "djui_panel_confirm.h"
#include "djui_panel_cheats.h"
extern struct DjuiRoot* gDjuiRoot;
extern struct DjuiText* gDjuiPauseOptions;
void djui_init(void);
void djui_connect_menu_open(void);
void djui_render_patch(void);
void djui_render(void);

380
src/pc/djui/djui_base.c Normal file
View file

@ -0,0 +1,380 @@
#include <string.h>
#include "djui.h"
////////////////
// properties //
////////////////
void djui_base_set_visible(struct DjuiBase* base, bool visible) {
base->visible = visible;
}
void djui_base_set_enabled(struct DjuiBase* base, bool enabled) {
base->enabled = enabled;
if (base->interactable != NULL && base->interactable->on_enabled_change != NULL) {
base->interactable->on_enabled_change(base);
}
}
void djui_base_set_location(struct DjuiBase* base, f32 x, f32 y) {
base->x.value = x;
base->y.value = y;
}
void djui_base_set_location_type(struct DjuiBase* base, enum DjuiScreenValueType xType, enum DjuiScreenValueType yType) {
base->x.type = xType;
base->y.type = yType;
}
void djui_base_set_size(struct DjuiBase* base, f32 width, f32 height) {
base->width.value = width;
base->height.value = height;
}
void djui_base_set_size_type(struct DjuiBase* base, enum DjuiScreenValueType widthType, enum DjuiScreenValueType heightType) {
base->width.type = widthType;
base->height.type = heightType;
}
void djui_base_set_color(struct DjuiBase* base, u8 r, u8 g, u8 b, u8 a) {
base->color.r = r;
base->color.g = g;
base->color.b = b;
base->color.a = a;
}
void djui_base_set_border_width(struct DjuiBase* base, f32 width) {
base->borderWidth.value = width;
}
void djui_base_set_border_width_type(struct DjuiBase* base, enum DjuiScreenValueType widthType) {
base->borderWidth.type = widthType;
}
void djui_base_set_border_color(struct DjuiBase* base, u8 r, u8 g, u8 b, u8 a) {
base->borderColor.r = r;
base->borderColor.g = g;
base->borderColor.b = b;
base->borderColor.a = a;
}
void djui_base_set_padding(struct DjuiBase* base, f32 top, f32 right, f32 bottom, f32 left) {
base->padding.top.value = top;
base->padding.right.value = right;
base->padding.bottom.value = bottom;
base->padding.left.value = left;
}
void djui_base_set_padding_type(struct DjuiBase* base, enum DjuiScreenValueType topType, enum DjuiScreenValueType rightType, enum DjuiScreenValueType bottomType, enum DjuiScreenValueType leftType) {
base->padding.top.type = topType;
base->padding.right.type = rightType;
base->padding.bottom.type = bottomType;
base->padding.left.type = leftType;
}
void djui_base_set_alignment(struct DjuiBase* base, enum DjuiHAlign hAlign, enum DjuiVAlign vAlign) {
base->hAlign = hAlign;
base->vAlign = vAlign;
}
/////////////
// utility //
/////////////
static void djui_base_get_cursor_hover_location(struct DjuiBase* base, f32* x, f32* y) {
*x = (base->elem.x + base->elem.width * 3.0f / 4.0f);
*y = (base->elem.y + base->elem.height * 3.0f / 4.0f);
}
static void djui_base_clip(struct DjuiBase* base) {
struct DjuiBase* parent = base->parent;
struct DjuiBaseRect* comp = &base->comp;
struct DjuiBaseRect* clip = &base->clip;
clip->x = comp->x;
clip->y = comp->y;
clip->width = comp->width;
clip->height = comp->height;
if (parent == NULL) { return; }
clip->x = fmax(clip->x, parent->clip.x);
clip->y = fmax(clip->y, parent->clip.y);
clip->width = (comp->x + comp->width) - clip->x;
clip->height = (comp->y + comp->height) - clip->y;
clip->width = fmin(clip->width, (parent->clip.x + parent->clip.width) - clip->x);
clip->height = fmin(clip->height, (parent->clip.y + parent->clip.height) - clip->y);
}
static void djui_base_add_padding(struct DjuiBase* base) {
struct DjuiBaseRect* comp = &base->comp;
struct DjuiBaseRect* parentComp = &base->comp;
f32 tPad = (base->padding.top.type == DJUI_SVT_RELATIVE) ? parentComp->height * base->padding.top.value : base->padding.top.value;
f32 rPad = (base->padding.right.type == DJUI_SVT_RELATIVE) ? parentComp->width * base->padding.right.value : base->padding.right.value;
f32 bPad = (base->padding.bottom.type == DJUI_SVT_RELATIVE) ? parentComp->height * base->padding.bottom.value : base->padding.bottom.value;
f32 lPad = (base->padding.left.type == DJUI_SVT_RELATIVE) ? parentComp->width * base->padding.left.value : base->padding.left.value;
comp->x += lPad;
comp->y += tPad;
comp->height -= tPad + bPad;
comp->width -= lPad + rPad;
}
void djui_base_compute(struct DjuiBase* base) {
struct DjuiBase* parent = base->parent;
struct DjuiBaseRect* comp = &base->comp;
f32 x = (base->x.type == DJUI_SVT_RELATIVE) ? parent->comp.width * base->x.value : base->x.value;
f32 y = (base->y.type == DJUI_SVT_RELATIVE) ? parent->comp.height * base->y.value : base->y.value;
f32 width = (base->width.type == DJUI_SVT_RELATIVE) ? parent->comp.width * base->width.value : base->width.value;
f32 height = (base->height.type == DJUI_SVT_RELATIVE) ? parent->comp.height * base->height.value : base->height.value;
width = (base->width.type == DJUI_SVT_ASPECT_RATIO) ? height * base->width.value : width;
height = (base->height.type == DJUI_SVT_ASPECT_RATIO) ? width * base->height.value : height;
// horizontal alignment
if (base->hAlign == DJUI_HALIGN_CENTER) {
x += (parent->comp.width - width) / 2.0f;
} else if (base->hAlign == DJUI_HALIGN_RIGHT) {
x = parent->comp.width - width - x;
}
// vertical alignment
if (base->vAlign == DJUI_VALIGN_CENTER) {
y += (parent->comp.height - height) / 2.0f;
} else if (base->vAlign == DJUI_VALIGN_BOTTOM) {
y = parent->comp.height - height - y;
}
// offset comp on parent's location
if (base->parent != NULL) {
x += parent->comp.x;
y += parent->comp.y;
}
// set computed values
comp->x = x;
comp->y = y;
comp->width = width;
comp->height = height;
struct DjuiBaseRect* elem = &base->elem;
elem->x = x;
elem->y = y;
elem->width = width;
elem->height = height;
djui_base_clip(base);
}
static void djui_base_add_child(struct DjuiBase* parent, struct DjuiBase* base) {
if (parent == NULL) { return; }
// allocate linked list node
struct DjuiBaseChild* baseChild = malloc(sizeof(struct DjuiBaseChild));
baseChild->base = base;
baseChild->next = NULL;
// add it to the head
if (parent->child == NULL || parent->addChildrenToHead) {
baseChild->next = parent->child;
parent->child = baseChild;
return;
}
// add it to the tail
struct DjuiBaseChild* parentChild = parent->child;
while (parentChild != NULL) {
if (parentChild->next == NULL) {
parentChild->next = baseChild;
break;
}
parentChild = parentChild->next;
}
}
////////////
// render //
////////////
static f32 djui_base_render_border_piece(struct DjuiBase* base, f32 x1, f32 y1, f32 x2, f32 y2, bool isXBorder) {
struct DjuiBaseRect* clip = &base->clip;
x1 = fmax(x1, clip->x);
y1 = fmax(y1, clip->y);
x2 = fmin(x2, clip->x + clip->width);
y2 = fmin(y2, clip->y + clip->height);
if (x2 <= x1) { return 0; }
if (y2 <= y1) { return 0; }
// translate position
f32 translatedX = x1;
f32 translatedY = y1;
djui_gfx_position_translate(&translatedX, &translatedY);
create_dl_translation_matrix(DJUI_MTX_PUSH, translatedX, translatedY, 0);
// translate size
f32 translatedWidth = x2 - x1;
f32 translatedHeight = y2 - y1;
djui_gfx_scale_translate(&translatedWidth, &translatedHeight);
create_dl_scale_matrix(DJUI_MTX_NOPUSH, translatedWidth, translatedHeight, 1.0f);
// render
gDPSetEnvColor(gDisplayListHead++, base->borderColor.r, base->borderColor.g, base->borderColor.b, base->borderColor.a);
gSPDisplayList(gDisplayListHead++, dl_djui_simple_rect);
gSPPopMatrix(gDisplayListHead++, G_MTX_MODELVIEW);
return isXBorder ? fmax(x2 - x1, 0) : fmax(y2 - y1, 0);
}
static void djui_base_render_border(struct DjuiBase* base) {
struct DjuiBaseRect* comp = &base->comp;
struct DjuiBaseRect* clip = &base->clip;
struct DjuiBaseRect savedComp = base->comp;
f32 xBorderWidth = (base->borderWidth.type == DJUI_SVT_RELATIVE) ? (savedComp.width * base->borderWidth.value) : base->borderWidth.value;
f32 yBorderWidth = (base->borderWidth.type == DJUI_SVT_RELATIVE) ? (savedComp.height * base->borderWidth.value) : base->borderWidth.value;
xBorderWidth = fmin(xBorderWidth, savedComp.width / 2.0f);
yBorderWidth = fmin(yBorderWidth, savedComp.height / 2.0f);
comp->x += base->borderWidth.value;
comp->y += base->borderWidth.value;
comp->width -= base->borderWidth.value * 2.0f;
comp->height -= base->borderWidth.value * 2.0f;
f32 addClip = 0;
addClip = djui_base_render_border_piece(base, savedComp.x, savedComp.y, savedComp.x + savedComp.width, savedComp.y + yBorderWidth, false);
clip->y += addClip;
clip->height -= addClip;
addClip = djui_base_render_border_piece(base, savedComp.x, savedComp.y + savedComp.height - yBorderWidth, savedComp.x + savedComp.width, savedComp.y + savedComp.height, false);
clip->height -= addClip;
addClip = djui_base_render_border_piece(base, savedComp.x, savedComp.y, savedComp.x + xBorderWidth, savedComp.y + savedComp.height, true);
clip->x += addClip;
clip->width -= addClip;
addClip = djui_base_render_border_piece(base, savedComp.x + savedComp.width - xBorderWidth, savedComp.y, savedComp.x + savedComp.width, savedComp.y + savedComp.height, true);
clip->width -= addClip;
}
////////////
// events //
////////////
bool djui_base_render(struct DjuiBase* base) {
if (!base->visible) { return false; }
if (base->on_render_pre != NULL) {
bool skipRender = false;
base->on_render_pre(base, &skipRender);
if (skipRender) { return false; }
}
struct DjuiBaseRect* comp = &base->comp;
struct DjuiBaseRect* clip = &base->clip;
djui_base_compute(base);
if (comp->width <= 0) { return false; }
if (comp->height <= 0) { return false; }
if (clip->width <= 0) { return false; }
if (clip->height <= 0) { return false; }
if (base->borderWidth.value > 0 && base->borderColor.a > 0) {
djui_base_render_border(base);
}
if (clip->width < 0 || clip->height <= 0) { return false; }
if (base->render != NULL) {
base->render(base);
}
djui_base_add_padding(base);
// render all children
struct DjuiBaseChild* child = base->child;
bool hasChildRendered = false;
while (child != NULL) {
struct DjuiBaseChild* nextChild = child->next;
bool childRendered = djui_base_render(child->base);
if (base->abandonAfterChildRenderFail && !childRendered && hasChildRendered) { break; }
hasChildRendered = hasChildRendered || childRendered;
if (base->on_child_render != NULL) {
base->on_child_render(base, child->base);
}
child = nextChild;
}
return true;
}
void djui_base_destroy(struct DjuiBase* base) {
// remove myself from parent's linked list
if (base->parent != NULL) {
struct DjuiBaseChild* child = base->parent->child;
struct DjuiBaseChild* lastChild = NULL;
struct DjuiBaseChild* nextChild = NULL;
while (child != NULL) {
nextChild = child->next;
if (child->base == base) {
// adjust linked list
if (lastChild == NULL) {
base->parent->child = nextChild;
} else {
lastChild->next = nextChild;
}
// deallocate child node
free(child);
base->parent = NULL;
break;
}
// iterate
lastChild = child;
child = nextChild;
}
}
// destroy all children and our linked list
struct DjuiBaseChild* child = base->child;
while (child != NULL) {
struct DjuiBaseChild* nextChild = child->next;
child->base->parent = NULL;
djui_base_destroy(child->base);
free(child);
child = nextChild;
}
// deallocate interactable
if (base->interactable != NULL) {
free(base->interactable);
base->interactable = NULL;
}
// destroy this
base->destroy(base);
}
void djui_base_init(struct DjuiBase* parent, struct DjuiBase* base, void(*render)(struct DjuiBase*), void (*destroy)(struct DjuiBase*)) {
memset(base, 0, sizeof(struct DjuiBase));
base->parent = parent;
djui_base_set_visible(base, true);
djui_base_set_enabled(base, true);
djui_base_set_size(base, 64, 64);
djui_base_set_color(base, 255, 255, 255, 255);
base->get_cursor_hover_location = djui_base_get_cursor_hover_location;
base->render = render;
base->destroy = destroy;
djui_base_add_child(parent, base);
}

74
src/pc/djui/djui_base.h Normal file
View file

@ -0,0 +1,74 @@
#pragma once
#include "djui.h"
#pragma pack(1)
struct DjuiBaseRect {
f32 x;
f32 y;
f32 width;
f32 height;
};
#pragma pack(1)
struct DjuiBaseChild {
struct DjuiBase* base;
struct DjuiBaseChild* next;
};
#pragma pack(1)
struct DjuiBasePadding {
struct DjuiScreenValue top;
struct DjuiScreenValue right;
struct DjuiScreenValue bottom;
struct DjuiScreenValue left;
};
#pragma pack(1)
struct DjuiBase {
struct DjuiBase* parent;
struct DjuiBaseChild* child;
bool visible;
bool enabled;
struct DjuiScreenValue x;
struct DjuiScreenValue y;
struct DjuiScreenValue width;
struct DjuiScreenValue height;
struct DjuiColor color;
struct DjuiScreenValue borderWidth;
struct DjuiColor borderColor;
struct DjuiBasePadding padding;
enum DjuiHAlign hAlign;
enum DjuiVAlign vAlign;
struct DjuiBaseRect elem;
struct DjuiBaseRect comp;
struct DjuiBaseRect clip;
struct DjuiInteractable* interactable;
bool addChildrenToHead;
bool abandonAfterChildRenderFail;
s32 tag;
void (*get_cursor_hover_location)(struct DjuiBase*, f32* x, f32* y);
void (*on_child_render)(struct DjuiBase*, struct DjuiBase*);
void (*on_render_pre)(struct DjuiBase*, bool*);
void (*render)(struct DjuiBase*);
void (*destroy)(struct DjuiBase*);
};
void djui_base_set_visible(struct DjuiBase* base, bool visible);
void djui_base_set_enabled(struct DjuiBase* base, bool enabled);
void djui_base_set_location(struct DjuiBase* base, f32 x, f32 y);
void djui_base_set_location_type(struct DjuiBase* base, enum DjuiScreenValueType xType, enum DjuiScreenValueType yType);
void djui_base_set_size(struct DjuiBase* base, f32 width, f32 height);
void djui_base_set_size_type(struct DjuiBase* base, enum DjuiScreenValueType widthType, enum DjuiScreenValueType heightType);
void djui_base_set_color(struct DjuiBase* base, u8 r, u8 g, u8 b, u8 a);
void djui_base_set_border_width(struct DjuiBase* base, f32 width);
void djui_base_set_border_width_type(struct DjuiBase* base, enum DjuiScreenValueType widthType);
void djui_base_set_border_color(struct DjuiBase* base, u8 r, u8 g, u8 b, u8 a);
void djui_base_set_padding(struct DjuiBase* base, f32 top, f32 right, f32 bottom, f32 left);
void djui_base_set_padding_type(struct DjuiBase* base, enum DjuiScreenValueType topType, enum DjuiScreenValueType rightType, enum DjuiScreenValueType bottomType, enum DjuiScreenValueType leftType);
void djui_base_set_alignment(struct DjuiBase* base, enum DjuiHAlign hAlign, enum DjuiVAlign vAlign);
void djui_base_compute(struct DjuiBase* base);
bool djui_base_render(struct DjuiBase* base);
void djui_base_destroy(struct DjuiBase* base);
void djui_base_init(struct DjuiBase* parent, struct DjuiBase* base, void (*render)(struct DjuiBase*), void (*destroy)(struct DjuiBase*));

98
src/pc/djui/djui_bind.c Normal file
View file

@ -0,0 +1,98 @@
#include <stdio.h>
#include <string.h>
#include "djui.h"
#include "src/pc/controller/controller_api.h"
#include "audio_defines.h"
#include "audio/external.h"
#define VK_ESCAPE 1
static void djui_bind_button_on_click(struct DjuiBase* caller) {
struct DjuiButton* button = (struct DjuiButton*)caller;
djui_text_set_text(button->text, "...");
controller_get_raw_key(); // consume lingering controller button press
djui_interactable_set_binding(caller);
}
static void djui_bind_button_on_bind(struct DjuiBase* caller) {
struct DjuiButton* button = (struct DjuiButton*)caller;
struct DjuiBind* bind = (struct DjuiBind*) caller->parent->parent;
// get key
u32 key = controller_get_raw_key();
if (key == VK_INVALID) { return; }
// invalidate key
if (key == VK_ESCAPE) { key = VK_INVALID; }
for (int i = 0; i < MAX_BINDS; i++) {
if (i == button->base.tag) { continue; }
if (bind->configKey[i] == key) {
key = VK_INVALID;
}
}
// set key
bind->configKey[button->base.tag] = key;
char keyStr[5] = { 0 };
if (key != VK_INVALID) {
sprintf(keyStr, "%04x", key);
}
djui_text_set_text(button->text, keyStr);
djui_interactable_set_binding(NULL);
play_sound(SOUND_MENU_CHANGE_SELECT, gDefaultSoundArgs);
}
static void djui_bind_destroy(struct DjuiBase* base) {
struct DjuiBind* bind = (struct DjuiBind*)base;
free(bind);
}
struct DjuiBind* djui_bind_create(struct DjuiBase* parent, const char* message, unsigned int configKey[]) {
struct DjuiBind* bind = malloc(sizeof(struct DjuiBind));
struct DjuiBase* base = &bind->base;
bind->configKey = configKey;
djui_base_init(parent, base, NULL, djui_bind_destroy);
djui_base_set_size_type(&bind->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
djui_base_set_size(&bind->base, 1.0f, 32);
djui_base_set_color(&bind->base, 0, 0, 0, 0);
struct DjuiText* text = djui_text_create(&bind->base, message);
djui_base_set_alignment(&text->base, DJUI_HALIGN_LEFT, DJUI_VALIGN_CENTER);
djui_base_set_size_type(&text->base, DJUI_SVT_RELATIVE, DJUI_SVT_RELATIVE);
djui_base_set_size(&text->base, 0.3f, 1.0f);
djui_text_set_alignment(text, DJUI_HALIGN_LEFT, DJUI_VALIGN_BOTTOM);
djui_text_set_drop_shadow(text, 120, 120, 120, 64);
djui_base_set_color(&text->base, 200, 200, 200, 255);
bind->text = text;
struct DjuiRect* rect = djui_rect_create(&bind->base);
djui_base_set_alignment(&rect->base, DJUI_HALIGN_RIGHT, DJUI_VALIGN_CENTER);
djui_base_set_size_type(&rect->base, DJUI_SVT_RELATIVE, DJUI_SVT_RELATIVE);
djui_base_set_size(&rect->base, 0.7f, 1.0f);
djui_base_set_color(&rect->base, 0, 0, 0, 0);
bind->rect = rect;
for (int i = 0; i < MAX_BINDS; i++) {
unsigned int key = configKey[i];
char keyStr[5] = { 0 };
if (key != VK_INVALID) {
sprintf(keyStr, "%04x", key);
}
struct DjuiButton* button = djui_button_create(&rect->base, keyStr);
djui_base_set_size_type(&button->base, DJUI_SVT_RELATIVE, DJUI_SVT_RELATIVE);
djui_base_set_size(&button->base, 0.33f, 1.0f);
button->base.tag = i;
djui_interactable_hook_click(&button->base, djui_bind_button_on_click);
djui_interactable_hook_bind(&button->base, djui_bind_button_on_bind);
enum DjuiHAlign hAlign = DJUI_HALIGN_LEFT;
if (i > 0) { hAlign = (i == 1) ? DJUI_HALIGN_CENTER : DJUI_HALIGN_RIGHT; }
djui_base_set_alignment(&button->base, hAlign, DJUI_VALIGN_CENTER);
bind->buttons[i] = button;
}
return bind;
}

14
src/pc/djui/djui_bind.h Normal file
View file

@ -0,0 +1,14 @@
#pragma once
#include "djui.h"
#include "src/pc/configfile.h"
#pragma pack(1)
struct DjuiBind {
struct DjuiBase base;
struct DjuiText* text;
struct DjuiRect* rect;
struct DjuiButton* buttons[MAX_BINDS];
unsigned int* configKey;
};
struct DjuiBind* djui_bind_create(struct DjuiBase* parent, const char* message, unsigned int configKey[]);

72
src/pc/djui/djui_button.c Normal file
View file

@ -0,0 +1,72 @@
#include "djui.h"
static void djui_button_set_default_style(struct DjuiBase* base) {
struct DjuiButton* button = (struct DjuiButton*)base;
u8 borderBrightness = button->style ? 100 : 150;
u8 rectBrightness = button->style ? 150 : 222;
djui_base_set_border_color(base, borderBrightness, borderBrightness, borderBrightness, 255);
djui_base_set_color(&button->rect->base, rectBrightness, rectBrightness, rectBrightness, 255);
djui_base_set_location(&button->text->base, 0.0f, 0.0f);
}
void djui_button_set_style(struct DjuiButton* button, u8 style) {
button->style = style;
djui_button_set_default_style(&button->base);
}
static void djui_button_on_hover(struct DjuiBase* base) {
struct DjuiButton* button = (struct DjuiButton*)base;
djui_base_set_border_color(base, 0, 120, 215, 255);
djui_base_set_color(&button->rect->base, 229, 241, 251, 255);
djui_base_set_location(&button->text->base, -0.5f, -1.0f);
}
static void djui_button_on_hover_end(struct DjuiBase* base) {
djui_button_set_default_style(base);
}
static void djui_button_on_cursor_down_begin(struct DjuiBase* base, bool inputCursor) {
struct DjuiButton* button = (struct DjuiButton*)base;
djui_base_set_border_color(base, 0, 84, 153, 255);
djui_base_set_color(&button->rect->base, 204, 228, 247, 255);
djui_base_set_location(&button->text->base, 0.5f, 0.5f);
}
static void djui_button_on_cursor_down_end(struct DjuiBase* base) {
djui_button_set_default_style(base);
}
static void djui_button_destroy(struct DjuiBase* base) {
struct DjuiButton* button = (struct DjuiButton*)base;
free(button);
}
struct DjuiButton* djui_button_create(struct DjuiBase* parent, const char* message) {
struct DjuiButton* button = malloc(sizeof(struct DjuiButton));
struct DjuiBase* base = &button->base;
djui_base_init(parent, base, NULL, djui_button_destroy);
djui_base_set_size(base, 200, 64);
djui_base_set_border_width(base, 2);
djui_interactable_create(base);
djui_interactable_hook_hover(base, djui_button_on_hover, djui_button_on_hover_end);
djui_interactable_hook_cursor_down(base, djui_button_on_cursor_down_begin, NULL, djui_button_on_cursor_down_end);
button->style = 0;
struct DjuiRect* rect = djui_rect_create(&button->base);
djui_base_set_size_type(&rect->base, DJUI_SVT_RELATIVE, DJUI_SVT_RELATIVE);
djui_base_set_size(&rect->base, 1.0f, 1.0f);
button->rect = rect;
struct DjuiText* text = djui_text_create(&rect->base, message);
djui_base_set_size_type(&text->base, DJUI_SVT_RELATIVE, DJUI_SVT_RELATIVE);
djui_base_set_size(&text->base, 1.0f, 1.0f);
djui_base_set_color(&text->base, 11, 11, 11, 255);
djui_text_set_alignment(text, DJUI_HALIGN_CENTER, DJUI_VALIGN_CENTER);
djui_text_set_drop_shadow(text, 0, 0, 0, 64);
button->text = text;
djui_button_set_default_style(base);
return button;
}

14
src/pc/djui/djui_button.h Normal file
View file

@ -0,0 +1,14 @@
#pragma once
#include "djui.h"
#pragma pack(1)
struct DjuiButton {
struct DjuiBase base;
struct DjuiRect* rect;
struct DjuiText* text;
u8 style;
};
void djui_button_set_style(struct DjuiButton* button, u8 style);
struct DjuiButton* djui_button_create(struct DjuiBase* parent, const char* message);

135
src/pc/djui/djui_chat_box.c Normal file
View file

@ -0,0 +1,135 @@
#include <stdio.h>
#include <string.h>
#include "pc/network/network.h"
#include "djui.h"
struct DjuiChatBox* gDjuiChatBox = NULL;
bool gDjuiChatBoxFocus = false;
void djui_chat_box_render(struct DjuiBase* base) {
struct DjuiChatBox* chatBox = (struct DjuiChatBox*)base;
struct DjuiBase* ccBase = &chatBox->chatContainer->base;
djui_base_set_size(ccBase, 1.0f, chatBox->base.comp.height - 32 - 8);
}
static void djui_chat_box_destroy(struct DjuiBase* base) {
struct DjuiChatBox* chatBox = (struct DjuiChatBox*)base;
free(chatBox);
}
static void djui_chat_box_set_focus_style(void) {
djui_base_set_visible(&gDjuiChatBox->chatInput->base, gDjuiChatBoxFocus);
if (gDjuiChatBoxFocus) {
djui_interactable_set_input_focus(&gDjuiChatBox->chatInput->base);
}
djui_base_set_color(&gDjuiChatBox->chatFlow->base, 0, 0, 0, gDjuiChatBoxFocus ? 128 : 0);
}
static void djui_chat_box_input_enter(struct DjuiInputbox* chatInput) {
djui_interactable_set_input_focus(NULL);
if (strlen(chatInput->buffer) != 0) {
djui_chat_message_create_from(gNetworkPlayerLocal->globalIndex, chatInput->buffer);
network_send_chat(chatInput->buffer, gNetworkPlayerLocal->globalIndex);
}
djui_inputbox_set_text(chatInput, "");
djui_inputbox_select_all(chatInput);
if (gDjuiChatBoxFocus) { djui_chat_box_toggle(); }
}
static void djui_chat_box_input_escape(struct DjuiInputbox* chatInput) {
djui_inputbox_set_text(chatInput, "");
djui_inputbox_select_all(chatInput);
if (gDjuiChatBoxFocus) { djui_chat_box_toggle(); }
}
static bool djui_chat_box_input_on_key_down(struct DjuiBase* base, int scancode) {
if (gDjuiChatBox == NULL) { return false; }
f32 yMax = gDjuiChatBox->chatContainer->base.elem.height - gDjuiChatBox->chatFlow->base.height.value;
f32* yValue = &gDjuiChatBox->chatFlow->base.y.value;
bool canScrollUp = (*yValue > yMax);
bool canScrollDown = (*yValue < 0);
f32 pageAmount = gDjuiChatBox->chatFlow->base.elem.height / 3.0f;
switch (scancode) {
case SCANCODE_UP:
gDjuiChatBox->scrolling = true;
if (canScrollUp) { *yValue = fmax(*yValue - 15, yMax); }
return true;
case SCANCODE_DOWN:
gDjuiChatBox->scrolling = true;
if (canScrollDown) { *yValue = fmin(*yValue + 15, 0); }
return true;
case SCANCODE_PAGE_UP:
gDjuiChatBox->scrolling = true;
if (canScrollUp) { *yValue = fmax(*yValue - pageAmount, yMax); }
return true;
case SCANCODE_PAGE_DOWN:
gDjuiChatBox->scrolling = true;
if (canScrollDown) { *yValue = fmin(*yValue + pageAmount, 0); }
return true;
case SCANCODE_ENTER: djui_chat_box_input_enter(gDjuiChatBox->chatInput); return true;
case SCANCODE_ESCAPE: djui_chat_box_input_escape(gDjuiChatBox->chatInput); return true;
default: return djui_inputbox_on_key_down(base, scancode);
}
}
void djui_chat_box_toggle(void) {
if (gDjuiChatBox == NULL) { return; }
gDjuiChatBoxFocus = !gDjuiChatBoxFocus;
djui_chat_box_set_focus_style();
gDjuiChatBox->scrolling = false;
gDjuiChatBox->chatFlow->base.y.value = gDjuiChatBox->chatContainer->base.elem.height - gDjuiChatBox->chatFlow->base.height.value;
}
struct DjuiChatBox* djui_chat_box_create(void) {
if (gDjuiChatBox != NULL) {
djui_base_destroy(&gDjuiChatBox->base);
gDjuiChatBox = NULL;
}
struct DjuiChatBox* chatBox = malloc(sizeof(struct DjuiChatBox));
struct DjuiBase* base = &chatBox->base;
djui_base_init(&gDjuiRoot->base, base, djui_chat_box_render, djui_chat_box_destroy);
djui_base_set_size_type(base, DJUI_SVT_ABSOLUTE, DJUI_SVT_RELATIVE);
djui_base_set_size(base, 600, 1.0f);
djui_base_set_alignment(base, DJUI_HALIGN_LEFT, DJUI_VALIGN_TOP);
djui_base_set_color(base, 0, 0, 0, 0);
djui_base_set_padding(base, 0, 8, 8, 8);
struct DjuiRect* chatContainer = djui_rect_create(base);
struct DjuiBase* ccBase = &chatContainer->base;
djui_base_set_size_type(ccBase, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
djui_base_set_size(ccBase, 1.0f, 0);
djui_base_set_color(ccBase, 0, 0, 0, 0);
chatBox->chatContainer = chatContainer;
struct DjuiFlowLayout* chatFlow = djui_flow_layout_create(ccBase);
struct DjuiBase* cfBase = &chatFlow->base;
djui_base_set_location(cfBase, 0, 0);
djui_base_set_size_type(cfBase, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
djui_base_set_size(cfBase, 1.0f, 2);
djui_base_set_color(cfBase, 0, 0, 0, 128);
djui_base_set_padding(cfBase, 2, 2, 2, 2);
djui_flow_layout_set_margin(chatFlow, 2);
djui_flow_layout_set_flow_direction(chatFlow, DJUI_FLOW_DIR_UP);
cfBase->addChildrenToHead = true;
cfBase->abandonAfterChildRenderFail = true;
chatBox->chatFlow = chatFlow;
struct DjuiInputbox* chatInput = djui_inputbox_create(base, 200);
struct DjuiBase* ciBase = &chatInput->base;
djui_base_set_size_type(ciBase, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
djui_base_set_size(ciBase, 1.0f, 32);
djui_base_set_alignment(ciBase, DJUI_HALIGN_LEFT, DJUI_VALIGN_BOTTOM);
djui_interactable_hook_key(&chatInput->base, djui_chat_box_input_on_key_down, djui_inputbox_on_key_up);
chatBox->chatInput = chatInput;
gDjuiChatBox = chatBox;
djui_chat_box_set_focus_style();
return chatBox;
}

View file

@ -0,0 +1,17 @@
#pragma once
#include "djui.h"
#pragma pack(1)
struct DjuiChatBox {
struct DjuiBase base;
struct DjuiRect* chatContainer;
struct DjuiFlowLayout* chatFlow;
struct DjuiInputbox* chatInput;
bool scrolling;
};
extern struct DjuiChatBox* gDjuiChatBox;
extern bool gDjuiChatBoxFocus;
void djui_chat_box_toggle(void);
struct DjuiChatBox* djui_chat_box_create(void);

View file

@ -0,0 +1,91 @@
#include <stdio.h>
#include "pc/network/network.h"
#include "audio_defines.h"
#include "audio/external.h"
#include "game/mario_misc.h"
#include "djui.h"
#define DJUI_CHAT_LIFE_TIME 10.0f
static void djui_chat_message_render(struct DjuiBase* base) {
struct DjuiChatMessage* chatMessage = (struct DjuiChatMessage*)base;
struct DjuiBase* ctBase = &chatMessage->message->base;
f32 seconds = (clock() - chatMessage->createTime) / (f32)CLOCKS_PER_SEC;
f32 f = 1.0f;
if (seconds >= (DJUI_CHAT_LIFE_TIME - 1)) {
f = fmax(1.0f - (seconds - (DJUI_CHAT_LIFE_TIME - 1)), 0.0f);
f *= f;
f *= f;
}
if (gDjuiChatBoxFocus) {
djui_base_set_color(base, 0, 0, 0, 64);
djui_base_set_color(ctBase, 255, 255, 255, 255);
djui_text_set_drop_shadow(chatMessage->message, 0, 0, 0, 200);
djui_base_set_size_type(base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
djui_base_set_size(base, 1.0f, chatMessage->base.height.value);
} else {
djui_base_set_color(base, 0, 0, 0, 150 * f);
djui_base_set_color(ctBase, 255, 255, 255, 255 * f);
djui_text_set_drop_shadow(chatMessage->message, 0, 0, 0, 200 * f);
djui_base_set_size_type(base, DJUI_SVT_ABSOLUTE, DJUI_SVT_ABSOLUTE);
djui_base_set_size(base, chatMessage->messageWidth, chatMessage->base.height.value);
}
djui_rect_render(base);
}
static void djui_chat_message_destroy(struct DjuiBase* base) {
struct DjuiChatMessage* chatMessage = (struct DjuiChatMessage*)base;
free(chatMessage);
}
struct DjuiChatMessage* djui_chat_message_create_from(u8 globalIndex, char* message) {
u8* rgb = get_player_color(globalIndex, 0);
u8 rgb2[3] = { 0 };
for (int i = 0; i < 3; i++) { rgb2[i] = fmin((f32)rgb[i] * 1.3f + 32.0f, 255); }
char chatMsg[256] = { 0 };
snprintf(chatMsg, 256, "\\#%02x%02x%02x\\%s:\\#dcdcdc\\ %s", rgb2[0], rgb2[1], rgb2[2], "Player", message);
play_sound((globalIndex == gNetworkPlayerLocal->globalIndex) ? SOUND_MENU_MESSAGE_DISAPPEAR : SOUND_MENU_MESSAGE_APPEAR, gDefaultSoundArgs);
return djui_chat_message_create(chatMsg);
}
struct DjuiChatMessage* djui_chat_message_create(char* message) {
struct DjuiChatMessage* chatMessage = malloc(sizeof(struct DjuiChatMessage));
struct DjuiBase* base = &chatMessage->base;
djui_base_init(&gDjuiChatBox->chatFlow->base, base, djui_chat_message_render, djui_chat_message_destroy);
djui_base_set_size_type(base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
djui_base_set_size(base, 1.0f, 0);
djui_base_set_color(base, 0, 0, 0, 64);
djui_base_set_padding(base, 2, 4, 2, 4);
djui_base_set_alignment(base, DJUI_HALIGN_LEFT, DJUI_VALIGN_BOTTOM);
f32 maxTextWidth = gDjuiChatBox->base.width.value - gDjuiChatBox->base.padding.left.value - gDjuiChatBox->base.padding.right.value - base->padding.left.value - base->padding.right.value;
struct DjuiText* chatText = djui_text_create(base, message);
struct DjuiBase* ctBase = &chatText->base;
djui_base_set_size_type(ctBase, DJUI_SVT_ABSOLUTE, DJUI_SVT_RELATIVE);
djui_base_set_size(ctBase, maxTextWidth, 1.0f);
djui_base_set_color(ctBase, 255, 255, 255, 255);
djui_base_set_location(ctBase, 0, 0);
djui_text_set_alignment(chatText, DJUI_HALIGN_LEFT, DJUI_VALIGN_TOP);
djui_text_set_drop_shadow(chatText, 0, 0, 0, 200);
chatMessage->message = chatText;
chatMessage->createTime = clock();
// figure out chat message height
chatText->base.comp.width = maxTextWidth;
f32 messageHeight = djui_text_count_lines(chatText, 10) * (chatText->font->lineHeight * chatText->font->defaultFontScale) + 8;
djui_base_set_size(base, 1.0f, messageHeight);
gDjuiChatBox->chatFlow->base.height.value += messageHeight + gDjuiChatBox->chatFlow->margin.value;
if (!gDjuiChatBox->scrolling) {
gDjuiChatBox->chatFlow->base.y.value = gDjuiChatBox->chatContainer->base.elem.height - gDjuiChatBox->chatFlow->base.height.value;
}
// figure out chat message width
f32 messageWidth = djui_text_find_width(chatText, 10);
chatMessage->messageWidth = messageWidth + 8;
return chatMessage;
}

View file

@ -0,0 +1,14 @@
#pragma once
#include "djui.h"
#include <time.h>
#pragma pack(1)
struct DjuiChatMessage {
struct DjuiBase base;
struct DjuiText* message;
f32 messageWidth;
clock_t createTime;
};
struct DjuiChatMessage* djui_chat_message_create_from(u8 globalIndex, char* message);
struct DjuiChatMessage* djui_chat_message_create(char* message);

View file

@ -0,0 +1,91 @@
#include "djui.h"
static void djui_checkbox_set_default_style(struct DjuiBase* base) {
struct DjuiCheckbox* checkbox = (struct DjuiCheckbox*)base;
djui_base_set_border_color(&checkbox->rect->base, 173, 173, 173, 255);
djui_base_set_color(&checkbox->rect->base, 0, 0, 0, 0);
djui_base_set_color(&checkbox->text->base, 200, 200, 200, 255);
djui_base_set_color(&checkbox->rectValue->base, 200, 200, 200, 255);
}
static void djui_checkbox_on_hover(struct DjuiBase* base) {
struct DjuiCheckbox* checkbox = (struct DjuiCheckbox*)base;
djui_base_set_border_color(&checkbox->rect->base, 0, 120, 215, 255);
djui_base_set_color(&checkbox->text->base, 229, 241, 251, 255);
djui_base_set_color(&checkbox->rectValue->base, 229, 241, 251, 255);
}
static void djui_checkbox_get_cursor_hover_location(struct DjuiBase* base, f32* x, f32* y) {
struct DjuiCheckbox* checkbox = (struct DjuiCheckbox*)base;
struct DjuiBase* rectBase = &checkbox->rect->base;
*x = (rectBase->elem.x + rectBase->elem.width * 3.0f / 4.0f);
*y = (rectBase->elem.y + rectBase->elem.height * 3.0f / 4.0f);
}
static void djui_checkbox_on_hover_end(struct DjuiBase* base) {
djui_checkbox_set_default_style(base);
}
static void djui_checkbox_on_cursor_down_begin(struct DjuiBase* base, bool inputCursor) {
struct DjuiCheckbox* checkbox = (struct DjuiCheckbox*)base;
djui_base_set_border_color(&checkbox->rect->base, 20, 170, 255, 255);
djui_base_set_color(&checkbox->rect->base, 255, 255, 255, 32);
djui_base_set_color(&checkbox->text->base, 229, 241, 251, 255);
djui_base_set_color(&checkbox->rectValue->base, 255, 255, 255, 255);
*checkbox->value = !(*checkbox->value);
djui_base_set_visible(&checkbox->rectValue->base, *checkbox->value);
if (base != NULL && base->interactable != NULL && base->interactable->on_value_change != NULL) {
base->interactable->on_value_change(base);
}
}
static void djui_checkbox_on_cursor_down_end(struct DjuiBase* base) {
struct DjuiCheckbox* checkbox = (struct DjuiCheckbox*)base;
djui_checkbox_set_default_style(base);
}
static void djui_checkbox_destroy(struct DjuiBase* base) {
struct DjuiCheckbox* checkbox = (struct DjuiCheckbox*)base;
free(checkbox);
}
struct DjuiCheckbox* djui_checkbox_create(struct DjuiBase* parent, const char* message, bool* value) {
struct DjuiCheckbox* checkbox = malloc(sizeof(struct DjuiCheckbox));
struct DjuiBase* base = &checkbox->base;
checkbox->value = value;
djui_base_init(parent, base, NULL, djui_checkbox_destroy);
djui_interactable_create(base);
djui_interactable_hook_hover(base, djui_checkbox_on_hover, djui_checkbox_on_hover_end);
djui_interactable_hook_cursor_down(base, djui_checkbox_on_cursor_down_begin, NULL, djui_checkbox_on_cursor_down_end);
struct DjuiText* text = djui_text_create(&checkbox->base, message);
djui_base_set_alignment(&text->base, DJUI_HALIGN_LEFT, DJUI_VALIGN_CENTER);
djui_base_set_size_type(&text->base, DJUI_SVT_RELATIVE, DJUI_SVT_RELATIVE);
djui_base_set_size(&text->base, 1.0f, 1.0f);
djui_text_set_alignment(text, DJUI_HALIGN_LEFT, DJUI_VALIGN_BOTTOM);
djui_text_set_drop_shadow(text, 120, 120, 120, 64);
checkbox->text = text;
struct DjuiRect* rect = djui_rect_create(&checkbox->base);
djui_base_set_alignment(&rect->base, DJUI_HALIGN_RIGHT, DJUI_VALIGN_CENTER);
djui_base_set_size_type(&rect->base, DJUI_SVT_ASPECT_RATIO, DJUI_SVT_RELATIVE);
djui_base_set_size(&rect->base, 1.0f, 1.0f);
djui_base_set_color(&rect->base, 0, 0, 0, 0);
djui_base_set_border_width(&rect->base, 2);
checkbox->rect = rect;
struct DjuiRect* rectValue = djui_rect_create(&rect->base);
djui_base_set_size_type(&rectValue->base, DJUI_SVT_ABSOLUTE, DJUI_SVT_ABSOLUTE);
djui_base_set_size(&rectValue->base, 16, 16);
djui_base_set_alignment(&rectValue->base, DJUI_HALIGN_CENTER, DJUI_VALIGN_CENTER);
djui_base_set_visible(&rectValue->base, *value);
checkbox->rectValue = rectValue;
djui_checkbox_set_default_style(base);
base->get_cursor_hover_location = djui_checkbox_get_cursor_hover_location;
return checkbox;
}

View file

@ -0,0 +1,13 @@
#pragma once
#include "djui.h"
#pragma pack(1)
struct DjuiCheckbox {
struct DjuiBase base;
struct DjuiRect* rect;
struct DjuiRect* rectValue;
struct DjuiText* text;
bool* value;
};
struct DjuiCheckbox* djui_checkbox_create(struct DjuiBase* parent, const char* message, bool* value);

152
src/pc/djui/djui_cursor.c Normal file
View file

@ -0,0 +1,152 @@
#include "djui.h"
#include "pc/controller/controller_mouse.h"
#include "pc/controller/controller_sdl.h"
extern ALIGNED8 u8 gd_texture_hand_open[];
extern ALIGNED8 u8 gd_texture_hand_closed[];
static struct DjuiImage* sMouseCursor = NULL;
static bool sCursorMouseControlled = false;
static struct DjuiBase* sInputControlledBase = NULL;
static f32 sSavedMouseX = 0;
static f32 sSavedMouseY = 0;
f32 gCursorX = 0;
f32 gCursorY = 0;
void djui_cursor_set_visible(bool visible) {
if (sMouseCursor) {
djui_base_set_visible(&sMouseCursor->base, visible);
}
sSavedMouseX = mouse_window_x;
sSavedMouseY = mouse_window_y;
}
bool djui_cursor_inside_base(struct DjuiBase* base) {
struct DjuiBaseRect* clip = &base->elem;
if (gCursorX < clip->x) { return false; }
if (gCursorX > clip->x + clip->width) { return false; }
if (gCursorY < clip->y) { return false; }
if (gCursorY > clip->y + clip->height) { return false; }
return true;
}
static void djui_cursor_base_hover_location(struct DjuiBase* base, f32* x, f32* y) {
base->get_cursor_hover_location(base, x, y);
}
void djui_cursor_input_controlled_center(struct DjuiBase* base) {
if (!sCursorMouseControlled) {
sInputControlledBase = base;
djui_cursor_set_visible(base != NULL);
}
}
static f32 djui_cursor_base_distance(struct DjuiBase* base, f32 xScale, f32 yScale) {
f32 x, y;
djui_cursor_base_hover_location(base, &x, &y);
x -= gCursorX;
y -= gCursorY;
return sqrtf((x * x) * xScale + (y * y) * yScale);
}
static void djui_cursor_move_check(s8 xDir, s8 yDir, struct DjuiBase** pick, struct DjuiBase* base) {
if (!base->visible) { return; }
if (!base->enabled) { return; }
if (base->interactable != NULL) {
f32 x1, y1, x2, y2;
x1 = base->elem.x;
y1 = base->elem.y;
x2 = base->elem.x + base->elem.width;
y2 = base->elem.y + base->elem.height;
bool xWithin = (gCursorX >= x1 && gCursorX <= x2) || sCursorMouseControlled;
bool yWithin = (gCursorY >= y1 && gCursorY <= y2) || sCursorMouseControlled;
bool valid = false;
if (yDir > 0 && gCursorY < y1 && xWithin) { valid = true; }
if (yDir < 0 && gCursorY > y2 && xWithin) { valid = true; }
if (xDir > 0 && gCursorX < x1 && yWithin) { valid = true; }
if (xDir < 0 && gCursorX > x2 && yWithin) { valid = true; }
f32 xH, yH;
djui_cursor_base_hover_location(base, &xH, &yH);
if (valid) {
if (*pick == NULL) {
*pick = base;
} else {
f32 pickDist = djui_cursor_base_distance(*pick, xDir ? 1.0f : 2.0f, yDir ? 1.0f : 2.0f);
f32 baseDist = djui_cursor_base_distance(base, xDir ? 1.0f : 2.0f, yDir ? 1.0f : 2.0f);
if (baseDist < pickDist) { *pick = base; }
}
}
}
// check all children
struct DjuiBaseChild* child = base->child;
while (child != NULL) {
djui_cursor_move_check(xDir, yDir, pick, child->base);
child = child->next;
}
}
void djui_cursor_move(s8 xDir, s8 yDir) {
if (xDir == 0 && yDir == 0) { return; }
struct DjuiBase* pick = NULL;
djui_cursor_move_check(xDir, yDir, &pick, &gDjuiRoot->base);
if (pick != NULL) {
sCursorMouseControlled = false;
djui_cursor_input_controlled_center(pick);
}
}
void djui_cursor_update(void) {
#if defined(CAPI_SDL2) || defined(CAPI_SDL1)
if (djui_interactable_is_binding()) { return; }
if (sMouseCursor == NULL) { return; }
if (!djui_panel_is_active()) { return; }
controller_sdl_read_mouse_window();
// check if mouse is in control again
static bool sFirstUpdate = true;
if (sFirstUpdate) {
sFirstUpdate = false;
sCursorMouseControlled = false;
sSavedMouseX = mouse_window_x;
sSavedMouseY = mouse_window_y;
} else if (!sCursorMouseControlled || (sMouseCursor && !sMouseCursor->base.visible)) {
f32 dist = sqrtf(powf(mouse_window_x - sSavedMouseX, 2) + powf(mouse_window_y - sSavedMouseY, 2));
if (dist > 5) {
sCursorMouseControlled = true;
djui_cursor_set_visible(true);
}
}
// update mouse cursor
if (sCursorMouseControlled) {
gCursorX = mouse_window_x;
gCursorY = mouse_window_y;
} else if (sInputControlledBase != NULL) {
djui_cursor_base_hover_location(sInputControlledBase, &gCursorX, &gCursorY);
}
// set cursor position
djui_base_set_location(&sMouseCursor->base, gCursorX - 13, gCursorY - 13);
// set cursor sprite
if ((gInteractablePad.button & PAD_BUTTON_A) || (mouse_window_buttons & MOUSE_BUTTON_1)) {
djui_image_set_image(sMouseCursor, gd_texture_hand_closed, 32, 32, 16);
} else {
djui_image_set_image(sMouseCursor, gd_texture_hand_open, 32, 32, 16);
}
#endif
djui_base_render(&sMouseCursor->base);
}
void djui_cursor_create(void) {
sMouseCursor = djui_image_create(NULL, gd_texture_hand_open, 32, 32, 16);
djui_base_set_location(&sMouseCursor->base, 0, 0);
djui_base_set_size(&sMouseCursor->base, 64, 64);
}

13
src/pc/djui/djui_cursor.h Normal file
View file

@ -0,0 +1,13 @@
#pragma once
#include "djui.h"
#include "djui_base.h"
extern f32 gCursorX;
extern f32 gCursorY;
void djui_cursor_set_visible(bool visible);
bool djui_cursor_inside_base(struct DjuiBase* base);
void djui_cursor_input_controlled_center(struct DjuiBase* base);
void djui_cursor_move(s8 xDir, s8 yDir);
void djui_cursor_update(void);
void djui_cursor_create(void);

View file

@ -0,0 +1,60 @@
#include "djui.h"
////////////////
// properties //
////////////////
void djui_flow_layout_set_flow_direction(struct DjuiFlowLayout* layout, enum DjuiFlowDirection flowDirection) {
layout->flowDirection = flowDirection;
}
void djui_flow_layout_set_margin(struct DjuiFlowLayout* layout, f32 margin) {
layout->margin.value = margin;
}
void djui_flow_layout_set_margin_type(struct DjuiFlowLayout* layout, enum DjuiScreenValueType marginType) {
layout->margin.type = marginType;
}
////////////
// events //
////////////
static void djui_flow_layout_on_child_render(struct DjuiBase* base, struct DjuiBase* child) {
struct DjuiFlowLayout* layout = (struct DjuiFlowLayout*)base;
switch (layout->flowDirection) {
case DJUI_FLOW_DIR_DOWN:
base->comp.y += (child->elem.height + layout->margin.value);
base->comp.height -= (child->elem.height + layout->margin.value);
break;
case DJUI_FLOW_DIR_UP:
base->comp.height -= (child->elem.height + layout->margin.value);
break;
case DJUI_FLOW_DIR_RIGHT:
base->comp.x += (child->elem.width + layout->margin.value);
base->comp.width -= (child->elem.width + layout->margin.value);
break;
case DJUI_FLOW_DIR_LEFT:
base->comp.width -= (child->elem.width + layout->margin.value);
break;
}
}
static void djui_flow_layout_destroy(struct DjuiBase* base) {
struct DjuiFlowLayout* layout = (struct DjuiFlowLayout*)base;
free(layout);
}
struct DjuiFlowLayout* djui_flow_layout_create(struct DjuiBase* parent) {
struct DjuiFlowLayout* layout = malloc(sizeof(struct DjuiFlowLayout));
struct DjuiBase* base = &layout->base;
djui_base_init(parent, base, djui_rect_render, djui_flow_layout_destroy);
djui_base_set_size(base, 256, 512);
djui_flow_layout_set_flow_direction(layout, DJUI_FLOW_DIR_DOWN);
djui_flow_layout_set_margin(layout, 8);
layout->base.on_child_render = djui_flow_layout_on_child_render;
return layout;
}

View file

@ -0,0 +1,15 @@
#pragma once
#include "djui.h"
#pragma pack(1)
struct DjuiFlowLayout {
struct DjuiBase base;
enum DjuiFlowDirection flowDirection;
struct DjuiScreenValue margin;
};
void djui_flow_layout_set_flow_direction(struct DjuiFlowLayout* layout, enum DjuiFlowDirection flowDirection);
void djui_flow_layout_set_margin(struct DjuiFlowLayout* layout, f32 margin);
void djui_flow_layout_set_margin_type(struct DjuiFlowLayout* layout, enum DjuiScreenValueType marginType);
struct DjuiFlowLayout* djui_flow_layout_create(struct DjuiBase* parent);

98
src/pc/djui/djui_font.c Normal file
View file

@ -0,0 +1,98 @@
#include "djui.h"
#include "game/segment2.h"
///////////////////////////////////
// font 0 (built-in normal font) //
///////////////////////////////////
static Vtx djui_font_normal_vertices[] = {
{{{ 0, -1, 0}, 0, { 0, 256}, { 0xff, 0xff, 0xff, 0xff }}},
{{{ 0.5f, -1, 0}, 0, { 0, 0}, { 0xff, 0xff, 0xff, 0xff }}},
{{{ 0.5f, 0, 0}, 0, { 512, 0}, { 0xff, 0xff, 0xff, 0xff }}},
{{{ 0, 0, 0}, 0, { 512, 256}, { 0xff, 0xff, 0xff, 0xff }}},
};
static const Gfx djui_font_normal_text_begin[] = {
gsDPPipeSync(),
gsSPClearGeometryMode(G_LIGHTING),
gsDPSetCombineMode(G_CC_FADEA, G_CC_FADEA),
gsDPSetEnvColor(255, 255, 255, 255),
gsDPSetRenderMode(G_RM_XLU_SURF, G_RM_XLU_SURF2),
gsDPSetTextureFilter(G_TF_POINT),
gsSPTexture(0xFFFF, 0xFFFF, 0, G_TX_RENDERTILE, G_ON),
gsSPEndDisplayList(),
};
static const Gfx djui_font_normal_text_settings[] = {
gsDPSetTile(G_IM_FMT_IA, G_IM_SIZ_16b, 0, 0, G_TX_LOADTILE, 0, G_TX_WRAP | G_TX_NOMIRROR, 3, G_TX_NOLOD, G_TX_WRAP | G_TX_NOMIRROR, 4, G_TX_NOLOD),
gsDPLoadSync(),
gsDPLoadBlock(G_TX_LOADTILE, 0, 0, ((16 * 8 + G_IM_SIZ_4b_INCR) >> G_IM_SIZ_4b_SHIFT) - 1, CALC_DXT(16, G_IM_SIZ_4b_BYTES)),
gsDPSetTile(G_IM_FMT_IA, G_IM_SIZ_4b, 1, 0, G_TX_RENDERTILE, 0, G_TX_WRAP | G_TX_NOMIRROR, 3, G_TX_NOLOD, G_TX_WRAP | G_TX_NOMIRROR, 4, G_TX_NOLOD),
gsDPSetTileSize(0, 0, 0, (16 - 1) << G_TEXTURE_IMAGE_FRAC, (8 - 1) << G_TEXTURE_IMAGE_FRAC),
gsSPVertex(djui_font_normal_vertices, 4, 0),
gsSPExecuteDjui(G_TEXCLIP_DJUI),
gsSP2Triangles(0, 1, 2, 0x0, 0, 2, 3, 0x0),
gsSPEndDisplayList(),
};
static void djui_font_normal_render_char(char c) {
extern const u8* const font_normal_chars[];
void* fontChar = (void*)font_normal_chars[c - '!'];
if (fontChar == NULL) { fontChar = (void*)font_normal_chars[94]; }
gDPPipeSync(gDisplayListHead++);
gDPSetTextureImage(gDisplayListHead++, G_IM_FMT_IA, G_IM_SIZ_16b, 1, (void*)fontChar);
gSPDisplayList(gDisplayListHead++, djui_font_normal_text_settings);
}
static f32 djui_font_normal_char_width(char c) {
if (c == ' ') { return 0.30f; }
extern const f32 font_normal_widths[];
return font_normal_widths[c - '!'];
}
static const struct DjuiFont sDjuiFontNormal = {
.charWidth = 0.5f,
.charHeight = 1.0f,
.lineHeight = 0.8125f,
.defaultFontScale = 32.0f,
.rotatedUV = true,
.textBeginDisplayList = djui_font_normal_text_begin,
.render_char = djui_font_normal_render_char,
.char_width = djui_font_normal_char_width,
};
////////////////////////////////
// font 1 (custom title font) //
////////////////////////////////
static void djui_font_title_render_char(char c) {
extern const u8* const font_title_chars[];
djui_gfx_render_texture(font_title_chars[c - '!'], 64, 64, 32);
}
static f32 djui_font_title_char_width(char c) {
if (c == ' ') { return 0.30f; }
extern const f32 font_title_widths[];
return font_title_widths[c - '!'];
}
static const struct DjuiFont sDjuiFontTitle = {
.charWidth = 1.0f,
.charHeight = 0.9f,
.lineHeight = 0.7f,
.defaultFontScale = 64.0f,
.rotatedUV = false,
.textBeginDisplayList = NULL,
.render_char = djui_font_title_render_char,
.char_width = djui_font_title_char_width,
};
///////////////
// font list //
///////////////
struct DjuiFont gDjuiFonts[] = {
sDjuiFontNormal,
sDjuiFontTitle,
};

17
src/pc/djui/djui_font.h Normal file
View file

@ -0,0 +1,17 @@
#pragma once
#include "djui.h"
#pragma pack(1)
struct DjuiFont {
f32 charWidth;
f32 charHeight;
f32 lineHeight;
f32 defaultFontScale;
u8 textureBitSize;
bool rotatedUV;
const Gfx* textBeginDisplayList;
void (*render_char)(char);
f32 (*char_width)(char);
};
extern struct DjuiFont gDjuiFonts[];

29
src/pc/djui/djui_gbi.h Normal file
View file

@ -0,0 +1,29 @@
#pragma once
#define G_TEXCLIP_DJUI 0xe1
#define G_TEXOVERRIDE_DJUI 0xe0
#define G_EXECUTE_DJUI 0xdd
#define gSetClippingDjui(pkt, cmd, rot, x1, y1, x2, y2) \
{ \
Gfx *_g = (Gfx *)(pkt); \
_g->words.w0 = _SHIFTL(cmd, 24, 8) | _SHIFTL( x1, 16, 8) | \
_SHIFTL( y1, 8, 8) | _SHIFTL(rot, 0, 8); \
_g->words.w1 = _SHIFTL(x2, 16, 8) | _SHIFTL(y2, 8, 8); \
}
#define gSetOverrideDjui(pkt, cmd, texture, w, h, bitSize) \
{ \
Gfx *_g = (Gfx *)(pkt); \
_g->words.w0 = _SHIFTL(cmd, 24, 8) | _SHIFTL(w, 16, 8) | \
_SHIFTL(h, 8, 8) | _SHIFTL(bitSize, 0, 8); \
_g->words.w1 = (uintptr_t)(texture); \
}
#define gsSPExecuteDjui(word) \
{{ \
_SHIFTL(G_EXECUTE_DJUI, 24, 8), (unsigned int)(word) \
}}
#define gDPSetTextureClippingDjui(pkt, rot, x1, y1, x2, y2) gSetClippingDjui(pkt, G_TEXCLIP_DJUI, rot, x1, y1, x2, y2)
#define gDPSetTextureOverrideDjui(pkt, texture, w, h, bitSize) gSetOverrideDjui(pkt, G_TEXOVERRIDE_DJUI, texture, w, h, bitSize)

128
src/pc/djui/djui_gfx.c Normal file
View file

@ -0,0 +1,128 @@
#include <ultra64.h>
#include "sm64.h"
#include "djui.h"
#include "game/ingame_menu.h"
#include "game/segment2.h"
#include "src/pc/pc_main.h"
#include "src/pc/gfx/gfx_window_manager_api.h"
#include "gfx_dimensions.h"
static const Vtx vertex_djui_simple_rect[] = {
{{{ 0, -1, 0}, 0, { 0, 0 }, { 0xff, 0xff, 0xff, 0xff }}},
{{{ 1, -1, 0}, 0, { 0, 0 }, { 0xff, 0xff, 0xff, 0xff }}},
{{{ 1, 0, 0}, 0, { 0, 0 }, { 0xff, 0xff, 0xff, 0xff }}},
{{{ 0, 0, 0}, 0, { 0, 0 }, { 0xff, 0xff, 0xff, 0xff }}},
};
const Gfx dl_djui_simple_rect[] = {
gsDPPipeSync(),
gsSPClearGeometryMode(G_LIGHTING),
gsDPSetCombineMode(G_CC_FADE, G_CC_FADE),
gsDPSetRenderMode(G_RM_XLU_SURF, G_RM_XLU_SURF2),
gsSPVertex(vertex_djui_simple_rect, 4, 0),
gsSP2Triangles(0, 1, 2, 0x0, 0, 2, 3, 0x0),
gsSPEndDisplayList(),
};
/////////////////////////////////////////////
static const Vtx vertex_djui_image[] = {
{{{ 0, -1, 0 }, 0, { 0, 512 }, { 0xff, 0xff, 0xff, 0xff }}},
{{{ 1, -1, 0 }, 0, { 512, 512 }, { 0xff, 0xff, 0xff, 0xff }}},
{{{ 1, 0, 0 }, 0, { 512, 0 }, { 0xff, 0xff, 0xff, 0xff }}},
{{{ 0, 0, 0 }, 0, { 0, 0 }, { 0xff, 0xff, 0xff, 0xff }}},
};
const Gfx dl_djui_image[] = {
gsDPPipeSync(),
gsSPClearGeometryMode(G_LIGHTING),
gsDPSetCombineMode(G_CC_FADEA, G_CC_FADEA),
gsDPSetRenderMode(G_RM_XLU_SURF, G_RM_XLU_SURF2),
gsDPSetTextureFilter(G_TF_POINT),
gsSPTexture(0xFFFF, 0xFFFF, 0, G_TX_RENDERTILE, G_ON),
gsDPLoadTextureBlock(NULL, G_IM_FMT_RGBA, G_IM_SIZ_16b, 16, 16, 0, G_TX_CLAMP, G_TX_CLAMP, 5, 5, G_TX_NOLOD, G_TX_NOLOD),
gsSPExecuteDjui(G_TEXOVERRIDE_DJUI),
gsSPVertex(vertex_djui_image, 4, 0),
gsSPExecuteDjui(G_TEXCLIP_DJUI),
gsSP2Triangles(0, 1, 2, 0x0, 0, 2, 3, 0x0),
gsSPTexture(0xFFFF, 0xFFFF, 0, G_TX_RENDERTILE, G_OFF),
gsDPSetCombineMode(G_CC_SHADE, G_CC_SHADE),
gsSPEndDisplayList(),
};
static u8 djui_gfx_power_of_two(u32 value) {
switch (value) {
case 2: return 1;
case 4: return 2;
case 8: return 3;
case 16: return 4;
case 32: return 5;
case 64: return 6;
case 128: return 7;
case 256: return 8;
case 512: return 9;
case 1024: return 10;
default: return 11;
}
}
void djui_gfx_render_texture(const u8* texture, u32 w, u32 h, u32 bitSize) {
gDPSetTextureOverrideDjui(gDisplayListHead++, texture, djui_gfx_power_of_two(w), djui_gfx_power_of_two(h), bitSize);
gSPDisplayList(gDisplayListHead++, dl_djui_image);
}
/////////////////////////////////////////////
void djui_gfx_position_translate(f32* x, f32* y) {
u32 windowWidth, windowHeight;
wm_api->get_dimensions(&windowWidth, &windowHeight);
*x = GFX_DIMENSIONS_FROM_LEFT_EDGE(0) + *x * ((f32)SCREEN_HEIGHT / (f32)windowHeight);
*y = SCREEN_HEIGHT - *y * ((f32)SCREEN_HEIGHT / (f32)windowHeight);
}
void djui_gfx_scale_translate(f32* width, f32* height) {
u32 windowWidth, windowHeight;
wm_api->get_dimensions(&windowWidth, &windowHeight);
*width = *width * ((f32)SCREEN_HEIGHT / (f32)windowHeight);
*height = *height * ((f32)SCREEN_HEIGHT / (f32)windowHeight);
}
void djui_gfx_size_translate(f32* size) {
u32 windowWidth, windowHeight;
wm_api->get_dimensions(&windowWidth, &windowHeight);
*size = *size * ((f32)SCREEN_HEIGHT / (f32)windowHeight);
}
bool djui_gfx_add_clipping_specific(struct DjuiBase* base, bool rotatedUV, f32 dX, f32 dY, f32 dW, f32 dH) {
struct DjuiBaseRect* clip = &base->clip;
f32 clipX2 = clip->x + clip->width;
f32 clipY2 = clip->y + clip->height;
f32 dX2 = dX + dW;
f32 dY2 = dY + dH;
// completely clipped
if (dX2 < clip->x) { return true; }
if (dX > clipX2) { return true; }
if (dY2 < clip->y) { return true; }
if (dY > clipY2) { return true; }
f32 dClipX1 = fmax((clip->x - dX) / dW, 0);
f32 dClipY1 = fmax((clip->y - dY) / dH, 0);
f32 dClipX2 = fmax((dX - (clipX2 - dW)) / dW, 0);
f32 dClipY2 = fmax((dY - (clipY2 - dH)) / dH, 0);
if ((dClipX1 != 0) || (dClipY1 != 0) || (dClipX2 != 0) || (dClipY2 != 0)) {
gDPSetTextureClippingDjui(gDisplayListHead++, rotatedUV, (u8)(dClipX1 * 255), (u8)(dClipY1 * 255), (u8)(dClipX2 * 255), (u8)(dClipY2 * 255));
}
return false;
}
bool djui_gfx_add_clipping(struct DjuiBase* base) {
struct DjuiBaseRect* comp = &base->comp;
return djui_gfx_add_clipping_specific(base, false, comp->x, comp->y, comp->width, comp->height);
}

19
src/pc/djui/djui_gfx.h Normal file
View file

@ -0,0 +1,19 @@
#pragma once
#include "djui.h"
#include "djui_base.h"
#define DJUI_MTX_PUSH 1
#define DJUI_MTX_NOPUSH 2
extern const Gfx dl_djui_simple_rect[];
extern const Gfx dl_djui_img_begin[];
extern const Gfx dl_djui_img_end[];
void djui_gfx_render_texture(const u8* texture, u32 w, u32 h, u32 bitSize);
void djui_gfx_position_translate(f32* x, f32* y);
void djui_gfx_scale_translate(f32* width, f32* height);
void djui_gfx_size_translate(f32* size);
bool djui_gfx_add_clipping_specific(struct DjuiBase* base, bool rotatedUV, f32 dX, f32 dY, f32 dW, f32 dH);
bool djui_gfx_add_clipping(struct DjuiBase* base);

60
src/pc/djui/djui_image.c Normal file
View file

@ -0,0 +1,60 @@
#include "djui.h"
#include "game/segment2.h"
#include "src/pc/network/network.h"
////////////////
// properties //
////////////////
void djui_image_set_image(struct DjuiImage* image, const u8* texture, u16 textureWidth, u16 textureHeight, u16 textureBitSize) {
image->texture = texture;
image->textureWidth = textureWidth;
image->textureHeight = textureHeight;
image->textureBitSize = textureBitSize;
}
////////////
// events //
////////////
static void djui_image_render(struct DjuiBase* base) {
struct DjuiImage* image = (struct DjuiImage*)base;
struct DjuiBaseRect* comp = &base->comp;
struct DjuiBaseRect* clip = &base->clip;
// translate position
f32 translatedX = comp->x;
f32 translatedY = comp->y;
djui_gfx_position_translate(&translatedX, &translatedY);
create_dl_translation_matrix(DJUI_MTX_PUSH, translatedX, translatedY, 0);
// translate size
f32 translatedWidth = comp->width;
f32 translatedHeight = comp->height;
djui_gfx_scale_translate(&translatedWidth, &translatedHeight);
create_dl_scale_matrix(DJUI_MTX_NOPUSH, translatedWidth, translatedHeight, 1.0f);
// render
if (!djui_gfx_add_clipping(base)) {
gDPSetEnvColor(gDisplayListHead++, base->color.r, base->color.g, base->color.b, base->color.a);
djui_gfx_render_texture(image->texture, image->textureWidth, image->textureHeight, image->textureBitSize);
}
gSPPopMatrix(gDisplayListHead++, G_MTX_MODELVIEW);
}
static void djui_image_destroy(struct DjuiBase* base) {
struct DjuiImage* image = (struct DjuiImage*)base;
free(image);
}
struct DjuiImage* djui_image_create(struct DjuiBase* parent, const u8* texture, u16 textureWidth, u16 textureHeight, u16 textureBitSize) {
struct DjuiImage* image = malloc(sizeof(struct DjuiImage));
struct DjuiBase* base = &image->base;
djui_base_init(parent, base, djui_image_render, djui_image_destroy);
djui_image_set_image(image, texture, textureWidth, textureHeight, textureBitSize);
return image;
}

15
src/pc/djui/djui_image.h Normal file
View file

@ -0,0 +1,15 @@
#pragma once
#include "djui.h"
#pragma pack(1)
struct DjuiImage {
struct DjuiBase base;
const u8* texture;
u16 textureWidth;
u16 textureHeight;
u16 textureBitSize;
};
void djui_image_set_image(struct DjuiImage* image, const u8* texture, u16 textureWidth, u16 textureHeight, u16 textureBitSize);
struct DjuiImage* djui_image_create(struct DjuiBase* parent, const u8* texture, u16 textureWidth, u16 textureHeight, u16 textureBitSize);

540
src/pc/djui/djui_inputbox.c Normal file
View file

@ -0,0 +1,540 @@
#include <string.h>
#include <stdio.h>
#include "djui.h"
#include "pc/gfx/gfx_window_manager_api.h"
#include "pc/pc_main.h"
#include "game/segment2.h"
#include "pc/controller/controller_keyboard.h"
#define DJUI_INPUTBOX_YOFF (-2)
#define DJUI_INPUTBOX_MAX_BLINK 50
#define DJUI_INPUTBOX_MID_BLINK (DJUI_INPUTBOX_MAX_BLINK / 2)
#define DJUI_INPUTBOX_CURSOR_WIDTH (2.0f / 32.0f)
static u8 sHeldShift = 0;
static u8 sHeldControl = 0;
static u8 sCursorBlink = 0;
static void djui_inputbox_on_change(struct DjuiInputbox* inputbox) {
struct DjuiBase* base = &inputbox->base;
if (base != NULL && base->interactable != NULL && base->interactable->on_value_change != NULL) {
base->interactable->on_value_change(base);
}
}
void djui_inputbox_set_text_color(struct DjuiInputbox* inputbox, u8 r, u8 g, u8 b, u8 a) {
inputbox->textColor.r = r;
inputbox->textColor.g = g;
inputbox->textColor.b = b;
inputbox->textColor.a = a;
}
void djui_inputbox_set_text(struct DjuiInputbox* inputbox, char* text) {
snprintf(inputbox->buffer, inputbox->bufferSize, "%s", text);
}
void djui_inputbox_select_all(struct DjuiInputbox* inputbox) {
inputbox->selection[1] = 0;
inputbox->selection[0] = strlen(inputbox->buffer);
}
void djui_inputbox_hook_enter_press(struct DjuiInputbox* inputbox, void (*on_enter_press)(struct DjuiInputbox*)) {
inputbox->on_enter_press = on_enter_press;
}
void djui_inputbox_hook_escape_press(struct DjuiInputbox* inputbox, void (*on_escape_press)(struct DjuiInputbox*)) {
inputbox->on_escape_press = on_escape_press;
}
static void djui_inputbox_set_default_style(struct DjuiBase* base) {
struct DjuiInputbox* inputbox = (struct DjuiInputbox*)base;
if (inputbox->base.enabled) {
djui_base_set_border_color(base, 150, 150, 150, 255);
djui_base_set_color(&inputbox->base, 240, 240, 240, 255);
} else {
djui_base_set_border_color(base, 90, 90, 90, 255);
djui_base_set_color(&inputbox->base, 140, 140, 140, 255);
}
}
static void djui_inputbox_on_hover(struct DjuiBase* base) {
struct DjuiInputbox* inputbox = (struct DjuiInputbox*)base;
djui_base_set_border_color(base, 0, 120, 215, 255);
djui_base_set_color(&inputbox->base, 255, 255, 255, 255);
}
static void djui_inputbox_on_hover_end(struct DjuiBase* base) {
djui_inputbox_set_default_style(base);
}
static u16 djui_inputbox_get_cursor_index(struct DjuiInputbox* inputbox) {
struct DjuiBaseRect* comp = &inputbox->base.comp;
struct DjuiFont* font = &gDjuiFonts[0];
f32 cX = (gCursorX - (comp->x + inputbox->viewX)) / font->defaultFontScale;
f32 x = 0;
u16 index = 0;
for (u16 i = 0; i < inputbox->bufferSize; i++) {
char c = inputbox->buffer[i];
if (x < cX) {
index = i;
}
if (c == '\0') { break; }
x += font->char_width(c);
}
return index;
}
static void djui_inputbox_on_cursor_down(struct DjuiBase* base) {
struct DjuiInputbox* inputbox = (struct DjuiInputbox*)base;
u16 index = djui_inputbox_get_cursor_index(inputbox);
inputbox->selection[0] = index;
}
static void djui_inputbox_on_cursor_down_end(struct DjuiBase* base) {
djui_inputbox_set_default_style(base);
}
static void djui_inputbox_on_cursor_down_begin(struct DjuiBase* base, bool inputCursor) {
struct DjuiInputbox* inputbox = (struct DjuiInputbox*)base;
u16 index = djui_inputbox_get_cursor_index(inputbox);
u16 selLength = abs(inputbox->selection[0] - inputbox->selection[1]);
if (selLength != strlen(inputbox->buffer) || djui_interactable_is_input_focus(base)) {
inputbox->selection[0] = index;
inputbox->selection[1] = index;
djui_interactable_hook_cursor_down(base, djui_inputbox_on_cursor_down_begin, djui_inputbox_on_cursor_down, djui_inputbox_on_cursor_down_end);
} else {
djui_interactable_hook_cursor_down(base, djui_inputbox_on_cursor_down_begin, NULL, djui_inputbox_on_cursor_down_end);
}
sCursorBlink = 0;
djui_interactable_set_input_focus(base);
}
static u16 djui_inputbox_jump_word_left(char* msg, u16 len, u16 i) {
if (i == 0) { return i; }
s32 lastI = i;
bool seenNonSpace = false;
while (true) {
if (msg[i] == ' ' && seenNonSpace) { i = lastI; break; }
lastI = i;
i--;
if (i <= 0) { i = 0; break; }
if (msg[i] != ' ') { seenNonSpace = true; }
}
return i;
}
static u16 djui_inputbox_jump_word_right(char *msg, u16 len, u16 i) {
if (i >= len) { return len; }
bool seenSpace = false;
while (true) {
i++;
if (i >= len) { i = len; break; }
if (msg[i] != ' ' && seenSpace) { break; }
if (msg[i] == ' ') { seenSpace = true; }
};
return i;
}
static void djui_inputbox_delete_selection(struct DjuiInputbox *inputbox) {
u16 *sel = inputbox->selection;
char *msg = inputbox->buffer;
u16 len = strlen(msg);
if (sel[0] != sel[1]) {
u16 s1 = fmin(sel[0], sel[1]);
u16 s2 = fmax(sel[0], sel[1]);
memmove(&msg[s1], &msg[s2], (len + 1) - s2);
sel[0] = s1;
sel[1] = s1;
}
djui_inputbox_on_change(inputbox);
}
bool djui_inputbox_on_key_down(struct DjuiBase *base, int scancode) {
struct DjuiInputbox *inputbox = (struct DjuiInputbox *) base;
u16 *sel = inputbox->selection;
char *msg = inputbox->buffer;
u16 len = strlen(msg);
u16 s1 = fmin(sel[0], sel[1]);
u16 s2 = fmax(sel[0], sel[1]);
switch (scancode) {
case SCANCODE_CONTROL_LEFT: sHeldControl |= (1 << 0); return true;
case SCANCODE_CONTROL_RIGHT: sHeldControl |= (1 << 1); return true;
case SCANCODE_SHIFT_LEFT: sHeldShift |= (1 << 0); return true;
case SCANCODE_SHIFT_RIGHT: sHeldShift |= (1 << 1); return true;
}
if (scancode == SCANCODE_LEFT) {
if (sHeldControl) {
sel[0] = djui_inputbox_jump_word_left(msg, len, sel[0]);
} else if (sel[0] > 0) {
sel[0]--;
}
if (!sHeldShift) { sel[1] = sel[0]; }
sCursorBlink = 0;
return true;
}
if (scancode == SCANCODE_RIGHT) {
if (sHeldControl) {
sel[0] = djui_inputbox_jump_word_right(msg, len, sel[0]);
} else if (sel[0] < len) {
sel[0]++;
}
if (!sHeldShift) { sel[1] = sel[0]; }
sCursorBlink = 0;
return true;
}
if (scancode == SCANCODE_HOME) {
sel[0] = 0;
if (!sHeldShift) { sel[1] = sel[0]; }
sCursorBlink = 0;
return true;
}
if (scancode == SCANCODE_END) {
sel[0] = len;
if (!sHeldShift) { sel[1] = sel[0]; }
sCursorBlink = 0;
return true;
}
if (scancode == SCANCODE_BACKSPACE) {
if (sel[0] == sel[1]) {
if (sHeldControl) {
sel[0] = djui_inputbox_jump_word_left(msg, len, sel[0]);
} else if (sel[0] > 0) {
sel[0]--;
}
}
if (sel[0] != sel[1]) {
djui_inputbox_delete_selection(inputbox);
}
sCursorBlink = 0;
return true;
}
if (scancode == SCANCODE_DELETE) {
if (sel[0] == sel[1]) {
if (sHeldControl) {
sel[1] = djui_inputbox_jump_word_right(msg, len, sel[1]);
} else if (sel[1] < len) {
sel[1]++;
}
}
if (sel[0] != sel[1]) {
djui_inputbox_delete_selection(inputbox);
}
sCursorBlink = 0;
return true;
}
if ((sHeldControl && scancode == SCANCODE_V) || (sHeldShift && scancode == SCANCODE_INSERT)) {
djui_interactable_on_text_input(wm_api->get_clipboard_text());
sCursorBlink = 0;
return true;
}
if (sHeldControl && (scancode == SCANCODE_C || scancode == SCANCODE_X)) {
if (sel[0] != sel[1]) {
char clipboardText[256] = { 0 };
snprintf(clipboardText, fmin(256, 1 + s2 - s1), "%s", &msg[s1]);
wm_api->set_clipboard_text(clipboardText);
if (scancode == SCANCODE_X) {
djui_inputbox_delete_selection(inputbox);
sCursorBlink = 0;
}
}
return true;
}
if (sHeldControl && scancode == SCANCODE_A) {
inputbox->selection[0] = len;
inputbox->selection[1] = 0;
sCursorBlink = 0;
return true;
}
if (scancode == SCANCODE_ESCAPE) {
djui_interactable_set_input_focus(NULL);
if (inputbox->on_escape_press) {
inputbox->on_escape_press(inputbox);
}
return true;
}
if (scancode == SCANCODE_ENTER) {
djui_interactable_set_input_focus(NULL);
if (inputbox->on_enter_press) {
inputbox->on_enter_press(inputbox);
}
return true;
}
return true;
}
void djui_inputbox_on_key_up(struct DjuiBase *base, int scancode) {
switch (scancode) {
case SCANCODE_CONTROL_LEFT: sHeldControl &= ~(1 << 0); break;
case SCANCODE_CONTROL_RIGHT: sHeldControl &= ~(1 << 1); break;
case SCANCODE_SHIFT_LEFT: sHeldShift &= ~(1 << 0); break;
case SCANCODE_SHIFT_RIGHT: sHeldShift &= ~(1 << 1); break;
}
}
static void djui_inputbox_on_focus_begin(struct DjuiBase* base) {
sHeldControl = 0;
sHeldShift = 0;
wm_api->start_text_input();
}
static void djui_inputbox_on_focus_end(struct DjuiBase* base) {
wm_api->stop_text_input();
}
static void djui_inputbox_on_text_input(struct DjuiBase *base, char* text) {
struct DjuiInputbox *inputbox = (struct DjuiInputbox *) base;
char* msg = inputbox->buffer;
int msgLen = strlen(msg);
int textLen = strlen(text);
// truncate
if (textLen + msgLen >= inputbox->bufferSize) {
int space = (inputbox->bufferSize - msgLen);
if (space <= 1) { return; }
text[space - 1] = '\0';
textLen = space - 1;
}
// erase selection
if (inputbox->selection[0] != inputbox->selection[1]) {
djui_inputbox_delete_selection(inputbox);
}
// sanitize
char *t = text;
while (*t != '\0') {
if (*t == '\n') { *t = ' '; }
else if (*t == '\r') { *t = ' '; }
else if (*t == ' ') { ; }
else if (*t < '!' || *t > '~') { *t = '?'; }
t++;
}
// back up current message
char* sMsg = malloc(sizeof(char) * (inputbox->bufferSize));
memcpy(sMsg, msg, inputbox->bufferSize);
// insert text
u16 sel = inputbox->selection[0];
snprintf(&msg[sel], (inputbox->bufferSize - sel), "%s%s", text, &sMsg[sel]);
free(sMsg);
// adjust cursor
inputbox->selection[0] += strlen(text);
inputbox->selection[1] = inputbox->selection[0];
sCursorBlink = 0;
djui_inputbox_on_change(inputbox);
}
static void djui_inputbox_render_char(struct DjuiInputbox* inputbox, char c, f32* drawX, f32* additionalShift) {
struct DjuiBaseRect* comp = &inputbox->base.comp;
struct DjuiFont* font = &gDjuiFonts[0];
f32 dX = comp->x + *drawX;
f32 dY = comp->y + DJUI_INPUTBOX_YOFF;
f32 dW = font->charWidth * font->defaultFontScale;
f32 dH = font->charHeight * font->defaultFontScale;
f32 charWidth = font->char_width(c);
*drawX += charWidth * font->defaultFontScale;
if (c != ' ' && !djui_gfx_add_clipping_specific(&inputbox->base, font->rotatedUV, dX, dY, dW, dH)) {
if (*additionalShift > 0) {
create_dl_translation_matrix(DJUI_MTX_NOPUSH, *additionalShift, 0, 0);
*additionalShift = 0;
}
font->render_char(c);
}
*additionalShift += charWidth;
}
static void djui_inputbox_render_selection(struct DjuiInputbox* inputbox) {
struct DjuiFont* font = &gDjuiFonts[0];
// make selection well formed
u16 selection[2] = { 0 };
selection[0] = fmin(inputbox->selection[0], inputbox->selection[1]);
selection[1] = fmax(inputbox->selection[0], inputbox->selection[1]);
char* msg = inputbox->buffer;
f32 x = 0;
f32 width = 0;
for (u16 i = 0; i < selection[1]; i++) {
if (i < selection[0]) {
x += font->char_width(msg[i]);
} else {
width += font->char_width(msg[i]);
}
}
sCursorBlink = (sCursorBlink + 1) % DJUI_INPUTBOX_MAX_BLINK;
// render only cursor when there is no selection width
if (selection[0] == selection[1]) {
if (sCursorBlink < DJUI_INPUTBOX_MID_BLINK && djui_interactable_is_input_focus(&inputbox->base)) {
create_dl_translation_matrix(DJUI_MTX_PUSH, x - DJUI_INPUTBOX_CURSOR_WIDTH / 2.0f, -0.1f, 0);
create_dl_scale_matrix(DJUI_MTX_NOPUSH, DJUI_INPUTBOX_CURSOR_WIDTH, 0.8f, 1.0f);
gDPSetEnvColor(gDisplayListHead++, 0, 0, 0, 255);
gSPDisplayList(gDisplayListHead++, dl_djui_simple_rect);
gSPPopMatrix(gDisplayListHead++, G_MTX_MODELVIEW);
}
return;
}
// clip selection box
// note: this is incredibly confusing due to being in font-space instead of screen-space
f32 clipLow = -inputbox->viewX / font->defaultFontScale;
if (x < clipLow) {
width -= clipLow - x;
x = clipLow;
}
f32 clipHigh = (inputbox->base.clip.width / font->defaultFontScale) - x + clipLow;
if (width > clipHigh) {
width = clipHigh;
}
// render selection box
create_dl_translation_matrix(DJUI_MTX_PUSH, x, -0.1f, 0);
create_dl_scale_matrix(DJUI_MTX_NOPUSH, width, 0.8f, 1.0f);
gDPSetEnvColor(gDisplayListHead++, 0, 120, 215, 255);
gSPDisplayList(gDisplayListHead++, dl_djui_simple_rect);
gSPPopMatrix(gDisplayListHead++, G_MTX_MODELVIEW);
// render selection cursor
if (sCursorBlink < DJUI_INPUTBOX_MID_BLINK && djui_interactable_is_input_focus(&inputbox->base)) {
f32 cX = (inputbox->selection[0] < inputbox->selection[1]) ? x : (x + width);
create_dl_translation_matrix(DJUI_MTX_PUSH, cX - DJUI_INPUTBOX_CURSOR_WIDTH / 2.0f, -0.1f, 0);
create_dl_scale_matrix(DJUI_MTX_NOPUSH, DJUI_INPUTBOX_CURSOR_WIDTH, 0.8f, 1.0f);
gDPSetEnvColor(gDisplayListHead++, 255, 127, 0, 255);
gSPDisplayList(gDisplayListHead++, dl_djui_simple_rect);
gSPPopMatrix(gDisplayListHead++, G_MTX_MODELVIEW);
}
}
static void djui_inputbox_keep_selection_in_view(struct DjuiInputbox* inputbox) {
struct DjuiFont* font = &gDjuiFonts[0];
// calculate where our cursor is
f32 cursorX = inputbox->viewX;
char* msg = inputbox->buffer;
for (u16 i = 0; i < inputbox->selection[0]; i++) {
cursorX += font->char_width(msg[i]) * font->defaultFontScale;
}
// shift viewing window
if (cursorX > inputbox->base.comp.width) {
inputbox->viewX -= cursorX - inputbox->base.comp.width;
} else if (cursorX < 0) {
inputbox->viewX -= cursorX;
}
}
static void djui_inputbox_render(struct DjuiBase* base) {
struct DjuiInputbox* inputbox = (struct DjuiInputbox*)base;
struct DjuiBaseRect* comp = &base->comp;
struct DjuiFont* font = &gDjuiFonts[0];
djui_rect_render(base);
// shift the viewing window to keep the selection in view
djui_inputbox_keep_selection_in_view(inputbox);
// translate position
f32 translatedX = comp->x + inputbox->viewX;
f32 translatedY = comp->y + DJUI_INPUTBOX_YOFF;
djui_gfx_position_translate(&translatedX, &translatedY);
create_dl_translation_matrix(DJUI_MTX_PUSH, translatedX, translatedY, 0);
// compute font size
f32 translatedFontSize = font->defaultFontScale;
djui_gfx_size_translate(&translatedFontSize);
create_dl_scale_matrix(DJUI_MTX_NOPUSH, translatedFontSize, translatedFontSize, 1.0f);
// render selection
djui_inputbox_render_selection(inputbox);
// begin font
gSPDisplayList(gDisplayListHead++, font->textBeginDisplayList);
// set color
gDPSetEnvColor(gDisplayListHead++, inputbox->textColor.r, inputbox->textColor.g, inputbox->textColor.b, inputbox->textColor.a);
// make selection well formed
u16 selection[2] = { 0 };
selection[0] = fmin(inputbox->selection[0], inputbox->selection[1]);
selection[1] = fmax(inputbox->selection[0], inputbox->selection[1]);
// render text
char* msg = inputbox->buffer;
f32 drawX = inputbox->viewX;
f32 additionalShift = 0;
bool wasInsideSelection = false;
for (u16 i = 0; i < inputbox->bufferSize; i++) {
if (msg[i] == '\0') { break; }
// deal with seleciton color
if (selection[0] != selection[1]) {
bool insideSelection = (i >= selection[0]) && (i < selection[1]);
if (insideSelection && !wasInsideSelection) {
gDPSetEnvColor(gDisplayListHead++, 255, 255, 255, 255);
} else if (!insideSelection && wasInsideSelection) {
gDPSetEnvColor(gDisplayListHead++, inputbox->textColor.r, inputbox->textColor.g, inputbox->textColor.b, inputbox->textColor.a);
}
wasInsideSelection = insideSelection;
}
// render character
djui_inputbox_render_char(inputbox, msg[i], &drawX, &additionalShift);
}
gSPPopMatrix(gDisplayListHead++, G_MTX_MODELVIEW);
gSPDisplayList(gDisplayListHead++, dl_ia_text_end);
}
static void djui_inputbox_destroy(struct DjuiBase* base) {
struct DjuiInputbox* inputbox = (struct DjuiInputbox*)base;
free(inputbox->buffer);
free(inputbox);
}
struct DjuiInputbox* djui_inputbox_create(struct DjuiBase* parent, u16 bufferSize) {
struct DjuiInputbox* inputbox = malloc(sizeof(struct DjuiInputbox));
struct DjuiBase* base = &inputbox->base;
memset(inputbox, 0, sizeof(struct DjuiInputbox));
inputbox->bufferSize = bufferSize;
inputbox->buffer = malloc(sizeof(char) * bufferSize);
memset(inputbox->buffer, 0, sizeof(char) * bufferSize);
djui_base_init(parent, base, djui_inputbox_render, djui_inputbox_destroy);
djui_base_set_size(base, 200, 32);
djui_base_set_border_width(base, 2);
djui_inputbox_set_text_color(inputbox, 0, 0, 0, 255);
djui_interactable_create(base);
djui_interactable_hook_hover(base, djui_inputbox_on_hover, djui_inputbox_on_hover_end);
djui_interactable_hook_cursor_down(base, djui_inputbox_on_cursor_down_begin, djui_inputbox_on_cursor_down, djui_inputbox_on_cursor_down_end);
djui_interactable_hook_key(base, djui_inputbox_on_key_down, djui_inputbox_on_key_up);
djui_interactable_hook_focus(base, djui_inputbox_on_focus_begin, NULL, djui_inputbox_on_focus_end);
djui_interactable_hook_text_input(base, djui_inputbox_on_text_input);
djui_interactable_hook_enabled_change(base, djui_inputbox_set_default_style);
djui_inputbox_set_default_style(base);
return inputbox;
}

View file

@ -0,0 +1,24 @@
#pragma once
#include "djui.h"
#pragma pack(1)
struct DjuiInputbox {
struct DjuiBase base;
char* buffer;
u16 bufferSize;
u16 selection[2];
f32 viewX;
struct DjuiColor textColor;
void (*on_enter_press)(struct DjuiInputbox*);
void (*on_escape_press)(struct DjuiInputbox*);
};
void djui_inputbox_set_text_color(struct DjuiInputbox* inputbox, u8 r, u8 g, u8 b, u8 a);
void djui_inputbox_set_text(struct DjuiInputbox* inputbox, char* text);
void djui_inputbox_select_all(struct DjuiInputbox* inputbox);
void djui_inputbox_hook_enter_press(struct DjuiInputbox* inputbox, void (*on_enter_press)(struct DjuiInputbox*));
void djui_inputbox_hook_escape_press(struct DjuiInputbox* inputbox, void (*on_escape_press)(struct DjuiInputbox*));
bool djui_inputbox_on_key_down(struct DjuiBase* base, int scancode);
void djui_inputbox_on_key_up(struct DjuiBase* base, int scancode);
struct DjuiInputbox* djui_inputbox_create(struct DjuiBase* parent, u16 bufferSize);

View file

@ -0,0 +1,430 @@
#include <string.h>
#include <time.h>
#include "djui.h"
#include "src/pc/controller/controller_sdl.h"
#include "src/pc/controller/controller_mouse.h"
#include "src/pc/controller/controller_keyboard.h"
#include "audio_defines.h"
#include "audio/external.h"
enum PadHoldDirection { PAD_HOLD_DIR_NONE, PAD_HOLD_DIR_UP, PAD_HOLD_DIR_DOWN, PAD_HOLD_DIR_LEFT, PAD_HOLD_DIR_RIGHT };
static enum PadHoldDirection sKeyboardHoldDirection = PAD_HOLD_DIR_NONE;
static u16 sKeyboardButtons = 0;
static bool sIgnoreInteractableUntilCursorReleased = false;
static struct DjuiBase* sInteractableFocus = NULL;
static struct DjuiBase* sInteractableBinding = NULL;
static struct DjuiBase* sHovered = NULL;
static struct DjuiBase* sMouseDown = NULL;
bool gInteractableOverridePad = false;
OSContPad gInteractablePad = { 0 };
static OSContPad sLastInteractablePad = { 0 };
static int sLastMouseButtons = 0;
static void djui_interactable_on_click(struct DjuiBase* base) {
if (base == NULL) { return; }
if (base->interactable == NULL) { return; }
if (base->interactable->on_click == NULL) { return; }
base->interactable->on_click(base);
}
static void djui_interactable_on_hover(struct DjuiBase* base) {
if (base == NULL) { return; }
if (base->interactable == NULL) { return; }
if (base->interactable->on_hover == NULL) { return; }
base->interactable->on_hover(base);
}
static void djui_interactable_on_hover_end(struct DjuiBase* base) {
if (base == NULL) { return; }
if (base->interactable == NULL) { return; }
if (base->interactable->on_hover == NULL) { return; }
base->interactable->on_hover_end(base);
}
static void djui_interactable_on_cursor_down_begin(struct DjuiBase* base, bool inputCursor) {
if (base == NULL) { return; }
if (base->interactable == NULL) { return; }
if (base->interactable->on_cursor_down_begin == NULL) { return; }
if (sHovered != NULL) {
djui_interactable_on_hover_end(sHovered);
sHovered = NULL;
}
base->interactable->on_cursor_down_begin(base, inputCursor);
}
static void djui_interactable_on_cursor_down(struct DjuiBase* base) {
if (base == NULL) { return; }
if (base->interactable == NULL) { return; }
if (base->interactable->on_cursor_down == NULL) { return; }
base->interactable->on_cursor_down(base);
}
static void djui_interactable_on_cursor_down_end(struct DjuiBase* base) {
if (base == NULL) { return; }
if (base->interactable == NULL) { return; }
if (base->interactable->on_cursor_down_end == NULL) { return; }
base->interactable->on_cursor_down_end(base);
if (djui_cursor_inside_base(base)) {
djui_interactable_on_click(base);
}
}
static void djui_interactable_on_focus_begin(struct DjuiBase* base) {
if (base == NULL) { return; }
if (base->interactable == NULL) { return; }
if (base->interactable->on_focus_begin == NULL) { return; }
base->interactable->on_focus_begin(base);
}
static void djui_interactable_on_focus(struct DjuiBase* base) {
if (base == NULL) { return; }
if (base->interactable == NULL) { return; }
if (base->interactable->on_focus == NULL) { return; }
base->interactable->on_focus(base, &gInteractablePad);
}
static void djui_interactable_on_focus_end(struct DjuiBase* base) {
if (base == NULL) { return; }
if (base->interactable == NULL) { return; }
if (base->interactable->on_focus_end == NULL) { return; }
base->interactable->on_focus_end(base);
}
static void djui_interactable_on_value_change(struct DjuiBase* base) {
if (base == NULL) { return; }
if (base->interactable == NULL) { return; }
if (base->interactable->on_value_change == NULL) { return; }
base->interactable->on_value_change(base);
}
static void djui_interactable_on_bind(struct DjuiBase* base) {
if (base == NULL) { return; }
if (base->interactable == NULL) { return; }
if (base->interactable->on_bind == NULL) { return; }
base->interactable->on_bind(base);
}
static void djui_interactable_cursor_update_active(struct DjuiBase* base) {
if (!base->visible) { return; }
if (!base->enabled) { return; }
static struct DjuiBase* insideParent = NULL;
if (!djui_cursor_inside_base(base)) { return; }
if (base->interactable != NULL) {
sHovered = base;
insideParent = base;
} else if (insideParent == NULL) {
sHovered = NULL;
}
// check all children
struct DjuiBaseChild* child = base->child;
while (child != NULL) {
djui_interactable_cursor_update_active(child->base);
child = child->next;
}
if (insideParent == base) {
insideParent = NULL;
}
}
bool djui_interactable_is_binding(void) {
return sInteractableBinding != NULL;
}
void djui_interactable_set_binding(struct DjuiBase* base) {
sInteractableBinding = base;
djui_cursor_set_visible(base == NULL);
if (base == NULL) {
sIgnoreInteractableUntilCursorReleased = true;
}
}
void djui_interactable_set_input_focus(struct DjuiBase* base) {
djui_interactable_on_focus_end(base);
sInteractableFocus = base;
djui_interactable_on_focus_begin(base);
djui_cursor_set_visible(base == NULL);
}
bool djui_interactable_is_input_focus(struct DjuiBase* base) {
return sInteractableFocus == base;
}
bool djui_interactable_on_key_down(int scancode) {
bool keyFocused = (sInteractableFocus != NULL)
&& (sInteractableFocus->interactable != NULL)
&& (sInteractableFocus->interactable->on_key_down != NULL);
if (keyFocused) {
bool consume = sInteractableFocus->interactable->on_key_down(sInteractableFocus, scancode);
if (consume) {
sKeyboardHoldDirection = PAD_HOLD_DIR_NONE;
sKeyboardButtons = 0;
return true;
}
}
if (scancode == SCANCODE_ESCAPE) {
// pressed escape button on keyboard
djui_panel_back();
}
if (gDjuiChatBox != NULL && !gDjuiChatBoxFocus) {
bool pressChat = false;
for (int i = 0; i < MAX_BINDS; i++) {
if (scancode == (int)configKeyChat[i]) { pressChat = true; }
}
if (pressChat) {
djui_chat_box_toggle();
return true;
}
}
switch (scancode) {
case SCANCODE_UP: sKeyboardHoldDirection = PAD_HOLD_DIR_UP; return true;
case SCANCODE_DOWN: sKeyboardHoldDirection = PAD_HOLD_DIR_DOWN; return true;
case SCANCODE_LEFT: sKeyboardHoldDirection = PAD_HOLD_DIR_LEFT; return true;
case SCANCODE_RIGHT: sKeyboardHoldDirection = PAD_HOLD_DIR_RIGHT; return true;
case SCANCODE_ENTER: sKeyboardButtons |= PAD_BUTTON_A; return true;
}
return false;
}
void djui_interactable_on_key_up(int scancode) {
bool keyFocused = (sInteractableFocus != NULL)
&& (sInteractableFocus->interactable != NULL)
&& (sInteractableFocus->interactable->on_key_up != NULL);
if (keyFocused) {
sInteractableFocus->interactable->on_key_up(sInteractableFocus, scancode);
sKeyboardHoldDirection = PAD_HOLD_DIR_NONE;
sKeyboardButtons = 0;
return;
}
OSContPad* pad = &gInteractablePad;
switch (scancode) {
case SCANCODE_UP: if (sKeyboardHoldDirection == PAD_HOLD_DIR_UP) { sKeyboardHoldDirection = PAD_HOLD_DIR_NONE; pad->stick_y = 0; } break;
case SCANCODE_DOWN: if (sKeyboardHoldDirection == PAD_HOLD_DIR_DOWN) { sKeyboardHoldDirection = PAD_HOLD_DIR_NONE; pad->stick_y = 0; } break;
case SCANCODE_LEFT: if (sKeyboardHoldDirection == PAD_HOLD_DIR_LEFT) { sKeyboardHoldDirection = PAD_HOLD_DIR_NONE; pad->stick_x = 0; } break;
case SCANCODE_RIGHT: if (sKeyboardHoldDirection == PAD_HOLD_DIR_RIGHT) { sKeyboardHoldDirection = PAD_HOLD_DIR_NONE; pad->stick_x = 0; } break;
case SCANCODE_ENTER: sKeyboardButtons &= ~PAD_BUTTON_A; break;
}
}
void djui_interactable_on_text_input(char* text) {
if (sInteractableFocus == NULL) { return; }
if (sInteractableFocus->interactable == NULL) { return; }
if (sInteractableFocus->interactable->on_text_input == NULL) { return; }
sInteractableFocus->interactable->on_text_input(sInteractableFocus, text);
}
void djui_interactable_update_pad(void) {
OSContPad* pad = &gInteractablePad;
pad->button |= sKeyboardButtons;
static enum PadHoldDirection lastPadHoldDirection = PAD_HOLD_DIR_NONE;
static clock_t padHoldTimer = 0;
enum PadHoldDirection padHoldDirection = sKeyboardHoldDirection;
if (padHoldDirection != PAD_HOLD_DIR_NONE) {
switch (padHoldDirection) {
case PAD_HOLD_DIR_UP: pad->stick_x = 0; pad->stick_y = -64; break;
case PAD_HOLD_DIR_DOWN: pad->stick_x = 0; pad->stick_y = 64; break;
case PAD_HOLD_DIR_LEFT: pad->stick_x = -64; pad->stick_y = 0; break;
case PAD_HOLD_DIR_RIGHT: pad->stick_x = 64; pad->stick_y = 0; break;
default: break;
}
} else if (pad->stick_x == 0 && pad->stick_y == 0) {
padHoldDirection = PAD_HOLD_DIR_NONE;
} else if (abs(pad->stick_x) > abs(pad->stick_y)) {
padHoldDirection = (pad->stick_x < 0) ? PAD_HOLD_DIR_LEFT : PAD_HOLD_DIR_RIGHT;
} else {
padHoldDirection = (pad->stick_y > 0) ? PAD_HOLD_DIR_UP : PAD_HOLD_DIR_DOWN;
}
bool validPadHold = false;
if (padHoldDirection == PAD_HOLD_DIR_NONE) {
// nothing to do
} else if (padHoldDirection != lastPadHoldDirection) {
padHoldTimer = clock() + CLOCKS_PER_SEC * 0.25f;
validPadHold = true;
} else if (clock() > padHoldTimer) {
padHoldTimer = clock() + CLOCKS_PER_SEC * 0.10f;
validPadHold = true;
}
if (validPadHold && sInteractableFocus == NULL) {
switch (padHoldDirection) {
case PAD_HOLD_DIR_UP: djui_cursor_move( 0, -1); break;
case PAD_HOLD_DIR_DOWN: djui_cursor_move( 0, 1); break;
case PAD_HOLD_DIR_LEFT: djui_cursor_move(-1, 0); break;
case PAD_HOLD_DIR_RIGHT: djui_cursor_move( 1, 0); break;
default: break;
}
}
lastPadHoldDirection = padHoldDirection;
}
void djui_interactable_update(void) {
// update pad
djui_interactable_update_pad();
// prevent pressing buttons when they should be ignored
int mouseButtons = mouse_window_buttons;
u16 padButtons = gInteractablePad.button;
if (sIgnoreInteractableUntilCursorReleased) {
if ((padButtons & PAD_BUTTON_A) || (mouseButtons & MOUSE_BUTTON_1)) {
padButtons &= ~PAD_BUTTON_A;
mouseButtons &= ~MOUSE_BUTTON_1;
} else {
sIgnoreInteractableUntilCursorReleased = false;
}
}
// update focused
if (sInteractableFocus) {
u16 mainButtons = PAD_BUTTON_A | PAD_BUTTON_B;
if ((mouseButtons & MOUSE_BUTTON_1) && !(sLastMouseButtons && MOUSE_BUTTON_1) && !djui_cursor_inside_base(sInteractableFocus)) {
// clicked outside of focused
djui_interactable_set_input_focus(NULL);
} else if ((padButtons & mainButtons) && !(sLastInteractablePad.button & mainButtons)) {
// pressed main face button
djui_interactable_set_input_focus(NULL);
} else {
djui_interactable_on_focus(sInteractableFocus);
}
} else if ((padButtons & PAD_BUTTON_B) && !(sLastInteractablePad.button & PAD_BUTTON_B)) {
// pressed back button on controller
djui_panel_back();
} else if ((padButtons & PAD_BUTTON_START) && !(sLastInteractablePad.button & PAD_BUTTON_START)) {
// pressed start button
if (gDjuiPanelPauseCreated) { djui_panel_shutdown(); }
}
if (sInteractableBinding != NULL) {
djui_interactable_on_bind(sInteractableBinding);
} else if ((padButtons & PAD_BUTTON_A) || (mouseButtons & MOUSE_BUTTON_1)) {
// cursor down events
if (sHovered != NULL) {
sMouseDown = sHovered;
sHovered = NULL;
djui_interactable_on_cursor_down_begin(sMouseDown, !mouseButtons);
} else {
djui_interactable_on_cursor_down(sMouseDown);
}
} else {
// cursor up event
if (sMouseDown != NULL) {
djui_interactable_on_cursor_down_end(sMouseDown);
sMouseDown = NULL;
}
struct DjuiBase* lastHovered = sHovered;
sHovered = NULL;
djui_interactable_cursor_update_active(&gDjuiRoot->base);
if (lastHovered != sHovered) {
djui_interactable_on_hover_end(lastHovered);
play_sound(SOUND_MENU_MESSAGE_NEXT_PAGE, gDefaultSoundArgs);
}
djui_interactable_on_hover(sHovered);
}
sLastInteractablePad = gInteractablePad;
sLastMouseButtons = mouseButtons;
}
void djui_interactable_hook_hover(struct DjuiBase* base,
void (*on_hover)(struct DjuiBase*),
void (*on_hover_end)(struct DjuiBase*)) {
struct DjuiInteractable* interactable = base->interactable;
interactable->on_hover = on_hover;
interactable->on_hover_end = on_hover_end;
}
void djui_interactable_hook_cursor_down(struct DjuiBase* base,
void (*on_cursor_down_begin)(struct DjuiBase*, bool),
void (*on_cursor_down)(struct DjuiBase*),
void (*on_cursor_down_end)(struct DjuiBase*)) {
struct DjuiInteractable* interactable = base->interactable;
interactable->on_cursor_down_begin = on_cursor_down_begin;
interactable->on_cursor_down = on_cursor_down;
interactable->on_cursor_down_end = on_cursor_down_end;
}
void djui_interactable_hook_focus(struct DjuiBase* base,
void (*on_focus_begin)(struct DjuiBase*),
void (*on_focus)(struct DjuiBase*, OSContPad*),
void (*on_focus_end)(struct DjuiBase*)) {
struct DjuiInteractable* interactable = base->interactable;
interactable->on_focus_begin = on_focus_begin;
interactable->on_focus = on_focus;
interactable->on_focus_end = on_focus_end;
}
void djui_interactable_hook_click(struct DjuiBase* base,
void (*on_click)(struct DjuiBase*)) {
struct DjuiInteractable* interactable = base->interactable;
interactable->on_click = on_click;
}
void djui_interactable_hook_value_change(struct DjuiBase* base,
void (*on_value_change)(struct DjuiBase*)) {
struct DjuiInteractable* interactable = base->interactable;
interactable->on_value_change = on_value_change;
}
void djui_interactable_hook_bind(struct DjuiBase* base,
void (*on_bind)(struct DjuiBase*)) {
struct DjuiInteractable* interactable = base->interactable;
interactable->on_bind = on_bind;
}
void djui_interactable_hook_key(struct DjuiBase* base,
bool (*on_key_down)(struct DjuiBase*, int),
void (*on_key_up)(struct DjuiBase*, int)) {
struct DjuiInteractable *interactable = base->interactable;
interactable->on_key_down = on_key_down;
interactable->on_key_up = on_key_up;
}
void djui_interactable_hook_text_input(struct DjuiBase *base,
void (*on_text_input)(struct DjuiBase*, char*)) {
struct DjuiInteractable *interactable = base->interactable;
interactable->on_text_input = on_text_input;
}
void djui_interactable_hook_enabled_change(struct DjuiBase *base,
void (*on_enabled_change)(struct DjuiBase*)) {
struct DjuiInteractable *interactable = base->interactable;
interactable->on_enabled_change = on_enabled_change;
}
void djui_interactable_create(struct DjuiBase* base) {
if (base->interactable != NULL) {
free(base->interactable);
}
struct DjuiInteractable* interactable = malloc(sizeof(struct DjuiInteractable));
memset(interactable, 0, sizeof(struct DjuiInteractable));
base->interactable = interactable;
}

View file

@ -0,0 +1,89 @@
#pragma once
#include "djui.h"
#include "djui_base.h"
#define PAD_BUTTON_A ((u16)(1 << 15))
#define PAD_BUTTON_B ((u16)(1 << 14))
#define PAD_BUTTON_START ((u16)(1 << 12))
#define MOUSE_BUTTON_1 ((u16)(1 << 0))
#define SCANCODE_UP 328
#define SCANCODE_DOWN 336
#define SCANCODE_LEFT 331
#define SCANCODE_RIGHT 333
#define SCANCODE_PAGE_DOWN 337
#define SCANCODE_PAGE_UP 329
#define SCANCODE_ENTER 28
#define SCANCODE_SPACE 57
#define SCANCODE_ESCAPE 1
#pragma pack(1)
struct DjuiInteractable {
bool enabled;
void (*on_hover)(struct DjuiBase*);
void (*on_hover_end)(struct DjuiBase*);
void (*on_cursor_down_begin)(struct DjuiBase*, bool);
void (*on_cursor_down)(struct DjuiBase*);
void (*on_cursor_down_end)(struct DjuiBase*);
void (*on_focus_begin)(struct DjuiBase*);
void (*on_focus)(struct DjuiBase*, OSContPad*);
void (*on_focus_end)(struct DjuiBase*);
void (*on_click)(struct DjuiBase*);
void (*on_value_change)(struct DjuiBase*);
void (*on_bind)(struct DjuiBase*);
bool (*on_key_down)(struct DjuiBase*, int scancode);
void (*on_key_up)(struct DjuiBase*, int scancode);
void (*on_text_input)(struct DjuiBase*, char* text);
void (*on_enabled_change)(struct DjuiBase*);
};
extern bool gInteractableOverridePad;
extern OSContPad gInteractablePad;
bool djui_interactable_is_binding(void);
void djui_interactable_set_binding(struct DjuiBase* base);
void djui_interactable_set_input_focus(struct DjuiBase* base);
bool djui_interactable_is_input_focus(struct DjuiBase* base);
bool djui_interactable_on_key_down(int scancode);
void djui_interactable_on_key_up(int scancode);
void djui_interactable_on_text_input(char *text);
void djui_interactable_update(void);
void djui_interactable_hook_hover(struct DjuiBase* base,
void (*on_hover)(struct DjuiBase*),
void (*on_hover_end)(struct DjuiBase*));
void djui_interactable_hook_cursor_down(struct DjuiBase* base,
void (*on_cursor_down_begin)(struct DjuiBase*, bool),
void (*on_cursor_down)(struct DjuiBase*),
void (*on_cursor_down_end)(struct DjuiBase*));
void djui_interactable_hook_focus(struct DjuiBase* base,
void (*on_focus_begin)(struct DjuiBase*),
void (*on_focus)(struct DjuiBase*, OSContPad*),
void (*on_focus_end)(struct DjuiBase*));
void djui_interactable_hook_click(struct DjuiBase* base,
void (*on_click)(struct DjuiBase*));
void djui_interactable_hook_value_change(struct DjuiBase* base,
void (*on_value_change)(struct DjuiBase*));
void djui_interactable_hook_bind(struct DjuiBase* base,
void (*on_bind)(struct DjuiBase*));
void djui_interactable_hook_key(struct DjuiBase* base,
bool (*on_key_down)(struct DjuiBase*, int),
void (*on_key_up)(struct DjuiBase*, int));
void djui_interactable_hook_text_input(struct DjuiBase* base,
void (*on_text_input)(struct DjuiBase*, char*));
void djui_interactable_hook_enabled_change(struct DjuiBase *base,
void (*on_enabled_change)(struct DjuiBase*));
void djui_interactable_create(struct DjuiBase* base);

152
src/pc/djui/djui_panel.c Normal file
View file

@ -0,0 +1,152 @@
#include "djui.h"
#include "src/pc/utils/misc.h"
#include "audio_defines.h"
#include "audio/external.h"
struct DjuiPanel {
struct DjuiBase* base;
struct DjuiPanel* parent;
struct DjuiBase* defaultElementBase;
};
static struct DjuiPanel* sPanelList = NULL;
static struct DjuiPanel* sPanelRemoving = NULL;
static f32 sMoveAmount = 0;
bool djui_panel_is_active(void) {
return (sPanelList != NULL);
}
void djui_panel_add(struct DjuiBase* caller, struct DjuiBase* panelBase, struct DjuiBase* defaultElementBase) {
bool firstPanel = (sPanelList == NULL);
gDjuiPanelJoinMessageVisible = false;
// remember element that triggered this panel add
if (sPanelList != NULL) {
sPanelList->defaultElementBase = caller;
}
// hide second from the top immediately
if (sPanelList != NULL && sPanelList->parent != NULL) {
djui_base_set_visible(sPanelList->parent->base, false);
}
// allocate panel
struct DjuiPanel* panel = malloc(sizeof(struct DjuiPanel));
panel->parent = sPanelList;
panel->base = panelBase;
panel->defaultElementBase = defaultElementBase;
sPanelList = panel;
// deselect cursor input
djui_cursor_input_controlled_center(NULL);
// hide new panel off screen initially
djui_base_set_location(panelBase, 0, -gDjuiRoot->base.height.value);
// disable panels
djui_base_set_enabled(panel->base, false);
if (panel->parent != NULL) {
djui_base_set_enabled(panel->parent->base, false);
}
// reset move amount
sMoveAmount = 0;
if (firstPanel) {
djui_base_set_location(panelBase, 0, 0);
djui_cursor_input_controlled_center(panel->defaultElementBase);
djui_base_set_enabled(panel->base, true);
} else {
play_sound(SOUND_MENU_CLICK_FILE_SELECT, gDefaultSoundArgs);
}
}
void djui_panel_back(void) {
if (sPanelList == NULL) { return; }
if (sPanelList->parent == NULL) {
if (gDjuiPanelPauseCreated) { djui_panel_shutdown(); }
return;
}
// deselect cursor input
djui_cursor_input_controlled_center(NULL);
// remember which panel to remove
sPanelRemoving = sPanelList;
// disable old active
djui_base_set_enabled(sPanelRemoving->base, false);
// set the previous active
sPanelList = sPanelList->parent;
// reset move amount
sMoveAmount = 0;
// set new active as visible
djui_base_set_visible(sPanelList->base, true);
// play a sound
play_sound(SOUND_MENU_CLICK_FILE_SELECT, gDefaultSoundArgs);
gDjuiPanelJoinMessageVisible = false;
}
void djui_panel_update(void) {
if (sPanelList == NULL) { return; }
if (sPanelList->base == NULL) { return; }
if (sPanelList->base->elem.height == 0) { return; }
struct DjuiBase* activeBase = sPanelList->base;
struct DjuiBase* parentBase = (sPanelList->parent == NULL) ? NULL : sPanelList->parent->base;
struct DjuiBase* removingBase = (sPanelRemoving == NULL) ? NULL : sPanelRemoving->base;
float moveMax = activeBase->elem.height;
if (sMoveAmount >= moveMax) { return; }
sMoveAmount += moveMax / 10.0f;
if (sMoveAmount >= moveMax) {
sMoveAmount = moveMax;
if (parentBase != NULL) {
djui_base_set_visible(parentBase, false);
}
djui_base_set_enabled(activeBase, true);
djui_cursor_input_controlled_center(sPanelList->defaultElementBase);
if (removingBase != NULL) {
djui_base_destroy(removingBase);
free(sPanelRemoving);
sPanelRemoving = NULL;
}
}
if (removingBase != NULL) {
activeBase->y.value = moveMax - moveMax * smoothstep(0, moveMax, sMoveAmount);
if (sPanelRemoving != NULL) {
removingBase->y.value = activeBase->y.value - removingBase->elem.height;
}
} else if (parentBase != NULL) {
activeBase->y.value = moveMax * smoothstep(0, moveMax, sMoveAmount) - moveMax;
parentBase->y.value = activeBase->y.value + moveMax;
}
}
void djui_panel_shutdown(void) {
struct DjuiPanel* panel = sPanelList;
while (panel != NULL) {
struct DjuiPanel* next = panel->parent;
djui_base_destroy(panel->base);
free(panel);
panel = next;
}
sPanelList = NULL;
sPanelRemoving = NULL;
sMoveAmount = 0;
gInteractableOverridePad = false;
gDjuiPanelJoinMessageVisible = false;
gDjuiPanelMainCreated = false;
gDjuiPanelPauseCreated = false;
djui_cursor_set_visible(false);
}

11
src/pc/djui/djui_panel.h Normal file
View file

@ -0,0 +1,11 @@
#pragma once
#include "djui.h"
#define DJUI_DEFAULT_PANEL_WIDTH (410.0f + (16 * 2.0f))
#define DJUI_PANEL_HEADER_OFFSET (-8)
bool djui_panel_is_active(void);
void djui_panel_add(struct DjuiBase* caller, struct DjuiBase* panelBase, struct DjuiBase* defaultElementBase);
void djui_panel_back(void);
void djui_panel_update(void);
void djui_panel_shutdown(void);

View file

@ -0,0 +1,62 @@
#include "djui.h"
#include "src/pc/utils/misc.h"
#include "src/pc/configfile.h"
void djui_panel_camera_create(struct DjuiBase* caller) {
f32 bodyHeight = 32 * 10 + 64 * 1 + 16 * 10;
struct DjuiBase* defaultBase = NULL;
struct DjuiThreePanel* panel = djui_panel_menu_create(bodyHeight, "\\#ff0800\\C\\#1be700\\A\\#00b3ff\\M\\#ffef00\\E\\#ff0800\\R\\#1be700\\A");
struct DjuiFlowLayout* body = (struct DjuiFlowLayout*)djui_three_panel_get_body(panel);
{
struct DjuiCheckbox* checkbox1 = djui_checkbox_create(&body->base, "Free Camera", &configEnableCamera);
djui_base_set_size_type(&checkbox1->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
djui_base_set_size(&checkbox1->base, 1.0f, 32);
defaultBase = &checkbox1->base;
struct DjuiCheckbox* checkbox2 = djui_checkbox_create(&body->base, "Analog Camera", &configCameraAnalog);
djui_base_set_size_type(&checkbox2->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
djui_base_set_size(&checkbox2->base, 1.0f, 32);
struct DjuiCheckbox* checkbox3 = djui_checkbox_create(&body->base, "Mouse Look", &configCameraMouse);
djui_base_set_size_type(&checkbox3->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
djui_base_set_size(&checkbox3->base, 1.0f, 32);
struct DjuiCheckbox* checkbox4 = djui_checkbox_create(&body->base, "Invert X", &configCameraInvertX);
djui_base_set_size_type(&checkbox4->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
djui_base_set_size(&checkbox4->base, 1.0f, 32);
struct DjuiCheckbox* checkbox5 = djui_checkbox_create(&body->base, "Invert Y", &configCameraInvertY);
djui_base_set_size_type(&checkbox5->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
djui_base_set_size(&checkbox5->base, 1.0f, 32);
struct DjuiSlider* slider1 = djui_slider_create(&body->base, "X Sensitivity", &configCameraXSens, 1, 100);
djui_base_set_size_type(&slider1->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
djui_base_set_size(&slider1->base, 1.0f, 32);
struct DjuiSlider* slider2 = djui_slider_create(&body->base, "Y Sensitivity", &configCameraYSens, 1, 100);
djui_base_set_size_type(&slider2->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
djui_base_set_size(&slider2->base, 1.0f, 32);
struct DjuiSlider* slider3 = djui_slider_create(&body->base, "Aggression", &configCameraAggr, 0, 100);
djui_base_set_size_type(&slider3->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
djui_base_set_size(&slider3->base, 1.0f, 32);
struct DjuiSlider* slider4 = djui_slider_create(&body->base, "Pan Level", &configCameraPan, 0, 100);
djui_base_set_size_type(&slider4->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
djui_base_set_size(&slider4->base, 1.0f, 32);
struct DjuiSlider* slider5 = djui_slider_create(&body->base, "Deceleration", &configCameraDegrade, 0, 100);
djui_base_set_size_type(&slider5->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
djui_base_set_size(&slider5->base, 1.0f, 32);
struct DjuiButton* button6 = djui_button_create(&body->base, "Back");
djui_base_set_size_type(&button6->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
djui_base_set_size(&button6->base, 1.0f, 64);
djui_button_set_style(button6, 1);
djui_interactable_hook_click(&button6->base, djui_panel_menu_back);
}
djui_panel_add(caller, &panel->base, defaultBase);
}

View file

@ -0,0 +1,4 @@
#pragma once
#include "djui.h"
void djui_panel_camera_create(struct DjuiBase* caller);

View file

@ -0,0 +1,47 @@
#include "djui.h"
#include "pc/cheats.h"
void djui_panel_cheats_create(struct DjuiBase* caller) {
f32 bodyHeight = 32 * 5 + 64 * 1 + 16 * 6;
struct DjuiBase* defaultBase = NULL;
struct DjuiThreePanel* panel = djui_panel_menu_create(bodyHeight, "\\#ff0800\\C\\#1be700\\H\\#00b3ff\\E\\#ffef00\\A\\#ff0800\\T\\#1be700\\S");
struct DjuiFlowLayout* body = (struct DjuiFlowLayout*)djui_three_panel_get_body(panel);
{
{
struct DjuiCheckbox* checkbox = djui_checkbox_create(&body->base, "Moon jump", &Cheats.MoonJump);
djui_base_set_size_type(&checkbox->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
djui_base_set_size(&checkbox->base, 1.0f, 32);
defaultBase = &checkbox->base;
}
{
struct DjuiCheckbox* checkbox = djui_checkbox_create(&body->base, "God mode", &Cheats.GodMode);
djui_base_set_size_type(&checkbox->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
djui_base_set_size(&checkbox->base, 1.0f, 32);
}
{
struct DjuiCheckbox* checkbox = djui_checkbox_create(&body->base, "Infinite lives", &Cheats.InfiniteLives);
djui_base_set_size_type(&checkbox->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
djui_base_set_size(&checkbox->base, 1.0f, 32);
}
{
struct DjuiCheckbox* checkbox = djui_checkbox_create(&body->base, "Super speed", &Cheats.SuperSpeed);
djui_base_set_size_type(&checkbox->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
djui_base_set_size(&checkbox->base, 1.0f, 32);
}
{
struct DjuiCheckbox* checkbox = djui_checkbox_create(&body->base, "Responsive controls", &Cheats.Responsive);
djui_base_set_size_type(&checkbox->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
djui_base_set_size(&checkbox->base, 1.0f, 32);
}
struct DjuiButton* button1 = djui_button_create(&body->base, "Back");
djui_base_set_size_type(&button1->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
djui_base_set_size(&button1->base, 1.0f, 64);
djui_button_set_style(button1, 1);
djui_interactable_hook_click(&button1->base, djui_panel_menu_back);
}
djui_panel_add(caller, &panel->base, defaultBase);
}

View file

@ -0,0 +1,4 @@
#pragma once
#include "djui.h"
void djui_panel_cheats_create(struct DjuiBase* caller);

View file

@ -0,0 +1,38 @@
#include "djui.h"
#include "src/pc/utils/misc.h"
void djui_panel_confirm_create(struct DjuiBase* caller, char* title, char* message, void (*on_yes_click)(struct DjuiBase*)) {
f32 bodyHeight = 64 * 2 + 16 * 1;
struct DjuiBase* defaultBase = NULL;
struct DjuiThreePanel* panel = djui_panel_menu_create(bodyHeight, title);
struct DjuiFlowLayout* body = (struct DjuiFlowLayout*)djui_three_panel_get_body(panel);
{
struct DjuiText* text = djui_text_create(&body->base, message);
djui_base_set_size_type(&text->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
djui_base_set_size(&text->base, 1.0f, 64);
djui_base_set_color(&text->base, 200, 200, 200, 255);
djui_text_set_alignment(text, DJUI_HALIGN_CENTER, DJUI_VALIGN_CENTER);
struct DjuiRect* rect1 = djui_rect_create(&body->base);
djui_base_set_size_type(&rect1->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
djui_base_set_size(&rect1->base, 1.0f, 64);
djui_base_set_color(&rect1->base, 0, 0, 0, 0);
{
struct DjuiButton* button1 = djui_button_create(&rect1->base, "No");
djui_base_set_size_type(&button1->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
djui_base_set_size(&button1->base, 0.485f, 64);
djui_base_set_alignment(&button1->base, DJUI_HALIGN_LEFT, DJUI_VALIGN_TOP);
djui_interactable_hook_click(&button1->base, djui_panel_menu_back);
defaultBase = &button1->base;
struct DjuiButton* button2 = djui_button_create(&rect1->base, "Yes");
djui_base_set_size_type(&button2->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
djui_base_set_size(&button2->base, 0.485f, 64);
djui_base_set_alignment(&button2->base, DJUI_HALIGN_RIGHT, DJUI_VALIGN_TOP);
djui_interactable_hook_click(&button2->base, on_yes_click);
}
}
djui_panel_add(caller, &panel->base, defaultBase);
}

View file

@ -0,0 +1,5 @@
#pragma once
#include "djui.h"
void djui_panel_confirm_create(struct DjuiBase* caller, char* title, char* message, void (*on_yes_click)(struct DjuiBase*));

View file

@ -0,0 +1,49 @@
#include "djui.h"
#include "src/pc/utils/misc.h"
#include "src/pc/configfile.h"
void djui_panel_controls_create(struct DjuiBase* caller) {
f32 bindBodyHeight = 32 * 11 + 1 * 10;
f32 bodyHeight = bindBodyHeight + 16 * 3 + 32 * 2 + 64;
struct DjuiBase* defaultBase = NULL;
struct DjuiThreePanel* panel = djui_panel_menu_create(bodyHeight, "\\#ff0800\\C\\#1be700\\O\\#00b3ff\\N\\#ffef00\\T\\#ff0800\\R\\#1be700\\O\\#00b3ff\\L\\#ffef00\\S");
struct DjuiFlowLayout* body = (struct DjuiFlowLayout*)djui_three_panel_get_body(panel);
{
struct DjuiFlowLayout* bindBody = djui_flow_layout_create(&body->base);
djui_base_set_size_type(&bindBody->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
djui_base_set_size(&bindBody->base, 1.0f, bindBodyHeight);
djui_base_set_color(&bindBody->base, 0, 0, 0, 0);
djui_flow_layout_set_margin(bindBody, 1);
{
struct DjuiBind* bind1 = djui_bind_create(&bindBody->base, "A", configKeyA);
djui_bind_create(&bindBody->base, "B", configKeyB);
djui_bind_create(&bindBody->base, "Start", configKeyStart);
djui_bind_create(&bindBody->base, "L", configKeyL);
djui_bind_create(&bindBody->base, "R", configKeyR);
djui_bind_create(&bindBody->base, "Z", configKeyZ);
djui_bind_create(&bindBody->base, "C Up", configKeyCUp);
djui_bind_create(&bindBody->base, "C Down", configKeyCDown);
djui_bind_create(&bindBody->base, "C Left", configKeyCLeft);
djui_bind_create(&bindBody->base, "C Right", configKeyCRight);
djui_bind_create(&bindBody->base, "Chat", configKeyChat);
defaultBase = &bind1->buttons[0]->base;
}
struct DjuiSlider* slider1 = djui_slider_create(&body->base, "Deadzone", &configStickDeadzone, 0, 100);
djui_base_set_size_type(&slider1->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
djui_base_set_size(&slider1->base, 1.0f, 32);
struct DjuiSlider* slider2 = djui_slider_create(&body->base, "Rumble Strength", &configRumbleStrength, 0, 100);
djui_base_set_size_type(&slider2->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
djui_base_set_size(&slider2->base, 1.0f, 32);
struct DjuiButton* button6 = djui_button_create(&body->base, "Back");
djui_base_set_size_type(&button6->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
djui_base_set_size(&button6->base, 1.0f, 64);
djui_button_set_style(button6, 1);
djui_interactable_hook_click(&button6->base, djui_panel_menu_back);
}
djui_panel_add(caller, &panel->base, defaultBase);
}

View file

@ -0,0 +1,4 @@
#pragma once
#include "djui.h"
void djui_panel_controls_create(struct DjuiBase* caller);

View file

@ -0,0 +1,66 @@
#include "djui.h"
static struct DjuiRect* sDjuiRect = NULL;
static struct DjuiText* sDjuiText = NULL;
static struct DjuiRect* sDjuiRect2 = NULL;
static struct DjuiText* sDjuiText2 = NULL;
static void djui_panel_debug_render_pre(struct DjuiBase* base, bool* skipRender) {
static u32 sTimer = 0;
sTimer++;
if (sDjuiText != NULL) {
djui_base_set_location(&sDjuiText->base,
32.0f + cos(sTimer / 20.0f) * 100.0f,
32.0f + sin(sTimer / 62.0f) * 50.0f);
djui_text_set_font_scale(sDjuiText, 16.0f + sin((sTimer) / 72.0f) * 4.0f);
}
if (sDjuiText2 != NULL) {
djui_base_set_location(&sDjuiText2->base,
32.0f + cos(sTimer / 20.0f) * 100.0f,
32.0f + sin(sTimer / 62.0f) * 100.0f);
djui_text_set_font_scale(sDjuiText2, 64.0f + sin((sTimer) / 72.0f) * 8.0f);
}
}
void djui_panel_debug_create(void) {
sDjuiRect = djui_rect_create(&gDjuiRoot->base);
djui_base_set_location(&sDjuiRect->base, 64, 64);
djui_base_set_size(&sDjuiRect->base, 300, 100);
djui_base_set_color(&sDjuiRect->base, 0, 0, 0, 255);
djui_base_set_alignment(&sDjuiRect->base, DJUI_HALIGN_RIGHT, DJUI_VALIGN_TOP);
sDjuiRect->base.on_render_pre = djui_panel_debug_render_pre;
sDjuiText = djui_text_create(&sDjuiRect->base, "hello\nworld");
djui_base_set_location(&sDjuiText->base, 0, 0);
djui_base_set_size(&sDjuiText->base, 300, 300);
djui_base_set_color(&sDjuiText->base, 255, 255, 255, 255);
djui_text_set_drop_shadow(sDjuiText, 255, 0, 0, 255);
djui_text_set_alignment(sDjuiText, DJUI_HALIGN_LEFT, DJUI_VALIGN_TOP);
sDjuiRect2 = djui_rect_create(&gDjuiRoot->base);
djui_base_set_location(&sDjuiRect2->base, 64, 64);
djui_base_set_size(&sDjuiRect2->base, 300, 100);
djui_base_set_color(&sDjuiRect2->base, 100, 100, 100, 255);
djui_base_set_alignment(&sDjuiRect2->base, DJUI_HALIGN_RIGHT, DJUI_VALIGN_BOTTOM);
sDjuiText2 = djui_text_create(&sDjuiRect2->base, "hello\nworld");
djui_base_set_location(&sDjuiText2->base, 0, 0);
djui_base_set_size(&sDjuiText2->base, 400, 400);
djui_base_set_color(&sDjuiText2->base, 255, 255, 255, 255);
djui_text_set_drop_shadow(sDjuiText2, 255, 0, 0, 255);
djui_text_set_alignment(sDjuiText2, DJUI_HALIGN_LEFT, DJUI_VALIGN_TOP);
djui_text_set_font(sDjuiText2, &gDjuiFonts[1]);
struct DjuiText* alphabet = djui_text_create(&gDjuiRoot->base, "abcdefghijklmnopqrstuvwxyz\nABCDEFGHIJKLMNOPQRSTUVWXYZ\n01234567890\nthe quick brown fox jumps over the lazy dog\ngeqkbnfjsortelydg\nTHE QUICK BROWN FOX JUMPS OVER THE LAZY DOG\nGEQKBNFJSORTELYDG");
djui_base_set_location(&alphabet->base, 0, 0);
djui_base_set_size(&alphabet->base, 400, 400);
djui_base_set_size_type(&alphabet->base, DJUI_SVT_RELATIVE, DJUI_SVT_RELATIVE);
djui_base_set_size(&alphabet->base, 1, 1);
djui_base_set_color(&alphabet->base, 255, 255, 255, 255);
djui_text_set_drop_shadow(alphabet, 255, 0, 0, 255);
djui_text_set_alignment(alphabet, DJUI_HALIGN_CENTER, DJUI_VALIGN_CENTER);
djui_text_set_font(alphabet, &gDjuiFonts[1]);
djui_text_set_font_scale(alphabet, 64);
}

View file

@ -0,0 +1,4 @@
#pragma once
#include "djui.h"
void djui_panel_debug_create(void);

View file

@ -0,0 +1,45 @@
#include "djui.h"
#include "src/pc/utils/misc.h"
#include "src/pc/configfile.h"
static void djui_panel_display_apply(struct DjuiBase* caller) {
configWindow.settings_changed = true;
}
void djui_panel_display_create(struct DjuiBase* caller) {
f32 bodyHeight = 32 * 5 + 64 * 1 + 16 * 4;
struct DjuiBase* defaultBase = NULL;
struct DjuiThreePanel* panel = djui_panel_menu_create(bodyHeight, "\\#ff0800\\D\\#1be700\\I\\#00b3ff\\S\\#ffef00\\P\\#ff0800\\L\\#1be700\\A\\#00b3ff\\Y");
struct DjuiFlowLayout* body = (struct DjuiFlowLayout*)djui_three_panel_get_body(panel);
{
struct DjuiCheckbox* checkbox1 = djui_checkbox_create(&body->base, "Fullscreen", &configWindow.fullscreen);
djui_base_set_size_type(&checkbox1->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
djui_base_set_size(&checkbox1->base, 1.0f, 32);
djui_interactable_hook_value_change(&checkbox1->base, djui_panel_display_apply);
defaultBase = &checkbox1->base;
struct DjuiCheckbox* checkbox2 = djui_checkbox_create(&body->base, "VSync", &configWindow.vsync);
djui_base_set_size_type(&checkbox2->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
djui_base_set_size(&checkbox2->base, 1.0f, 32);
djui_interactable_hook_value_change(&checkbox2->base, djui_panel_display_apply);
struct DjuiCheckbox* checkbox4 = djui_checkbox_create(&body->base, "HUD", &configHUD);
djui_base_set_size_type(&checkbox4->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
djui_base_set_size(&checkbox4->base, 1.0f, 32);
char* choices[3] = { "Nearest", "Linear", "Tripoint" };
struct DjuiSelectionbox* selectionbox1 = djui_selectionbox_create(&body->base, "Filtering", choices, 3, &configFiltering);
djui_base_set_size_type(&selectionbox1->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
djui_base_set_size(&selectionbox1->base, 1.0f, 32);
struct DjuiButton* button6 = djui_button_create(&body->base, "Back");
djui_base_set_size_type(&button6->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
djui_base_set_size(&button6->base, 1.0f, 64);
djui_button_set_style(button6, 1);
djui_interactable_hook_click(&button6->base, djui_panel_menu_back);
}
djui_panel_add(caller, &panel->base, defaultBase);
}

View file

@ -0,0 +1,4 @@
#pragma once
#include "djui.h"
void djui_panel_display_create(struct DjuiBase* caller);

View file

@ -0,0 +1,178 @@
#include <stdio.h>
#include "djui.h"
#include "game/save_file.h"
#include "pc/network/network.h"
#include "pc/utils/misc.h"
#include "pc/configfile.h"
#include "pc/cheats.h"
#ifdef DISCORD_SDK
#define DJUI_HOST_NS_IS_SOCKET (configNetworkSystem == 1)
#else
#define DJUI_HOST_NS_IS_SOCKET (true)
#endif
struct DjuiInputbox* sInputboxPort = NULL;
static unsigned int sKnockbackIndex = 0;
static void djui_panel_host_network_system_change(struct DjuiBase* base) {
struct DjuiSelectionbox* selectionbox = (struct DjuiSelectionbox*)base;
djui_base_set_enabled(&sInputboxPort->base, DJUI_HOST_NS_IS_SOCKET);
}
static bool djui_panel_host_port_valid(void) {
char* buffer = sInputboxPort->buffer;
int port = 0;
while (*buffer != '\0') {
if (*buffer < '0' || *buffer > '9') { return false; }
port *= 10;
port += (*buffer - '0');
buffer++;
}
return port >= 1024 && port <= 65535;
}
static void djui_panel_host_port_text_change(struct DjuiBase* caller) {
struct DjuiInputbox* inputbox1 = (struct DjuiInputbox*)caller;
if (djui_panel_host_port_valid()) {
djui_inputbox_set_text_color(inputbox1, 0, 0, 0, 255);
} else {
djui_inputbox_set_text_color(inputbox1, 255, 0, 0, 255);
}
}
static void djui_panel_host_knockback_change(struct DjuiBase* caller) {
switch (sKnockbackIndex) {
case 0: configPlayerKnockbackStrength = 10; break;
case 1: configPlayerKnockbackStrength = 25; break;
default: configPlayerKnockbackStrength = 75; break;
}
}
static void djui_panel_host_do_host(struct DjuiBase* caller) {
if (!djui_panel_host_port_valid()) {
djui_interactable_set_input_focus(&sInputboxPort->base);
djui_inputbox_select_all(sInputboxPort);
return;
}
configHostPort = atoi(sInputboxPort->buffer);
djui_panel_host_message_create(caller);
}
void djui_panel_host_create(struct DjuiBase* caller) {
#ifdef DISCORD_SDK
f32 bodyHeight = 32 * 7 + 64 * 2 + 16 * 9;
#else
f32 bodyHeight = 32 * 6 + 64 * 2 + 16 * 8;
#endif
struct DjuiBase* defaultBase = NULL;
struct DjuiThreePanel* panel = djui_panel_menu_create(bodyHeight, "\\#ff0800\\H\\#1be700\\O\\#00b3ff\\S\\#ffef00\\T");
struct DjuiFlowLayout* body = (struct DjuiFlowLayout*)djui_three_panel_get_body(panel);
{
#ifdef DISCORD_SDK
char* nChoices[2] = { "Discord", "Direct Connection" };
struct DjuiSelectionbox* selectionbox1 = djui_selectionbox_create(&body->base, "Network system", nChoices, 2, &configNetworkSystem);
djui_base_set_size_type(&selectionbox1->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
djui_base_set_size(&selectionbox1->base, 1.0f, 32);
djui_interactable_hook_value_change(&selectionbox1->base, djui_panel_host_network_system_change);
#endif
struct DjuiRect* rect1 = djui_rect_create(&body->base);
djui_base_set_size_type(&rect1->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
djui_base_set_size(&rect1->base, 1.0f, 32);
djui_base_set_color(&rect1->base, 0, 0, 0, 0);
{
struct DjuiText* text1 = djui_text_create(&rect1->base, "Port");
djui_base_set_size_type(&text1->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
djui_base_set_color(&text1->base, 200, 200, 200, 255);
djui_base_set_size(&text1->base, 0.485f, 64);
djui_base_set_alignment(&text1->base, DJUI_HALIGN_LEFT, DJUI_VALIGN_TOP);
struct DjuiInputbox* inputbox1 = djui_inputbox_create(&rect1->base, 32);
djui_base_set_size_type(&inputbox1->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
djui_base_set_size(&inputbox1->base, 0.5f, 32);
djui_base_set_alignment(&inputbox1->base, DJUI_HALIGN_RIGHT, DJUI_VALIGN_TOP);
char portString[32] = { 0 };
snprintf(portString, 32, "%d", configHostPort);
djui_inputbox_set_text(inputbox1, portString);
djui_interactable_hook_value_change(&inputbox1->base, djui_panel_host_port_text_change);
#ifdef DISCORD_SDK
djui_base_set_enabled(&inputbox1->base, DJUI_HOST_NS_IS_SOCKET);
#endif
sInputboxPort = inputbox1;
}
struct DjuiRect* rect2 = djui_rect_create(&body->base);
djui_base_set_size_type(&rect2->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
djui_base_set_size(&rect2->base, 1.0f, 32);
djui_base_set_color(&rect2->base, 0, 0, 0, 0);
{
struct DjuiText* text1 = djui_text_create(&rect2->base, "Save Slot");
djui_base_set_size_type(&text1->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
djui_base_set_color(&text1->base, 200, 200, 200, 255);
djui_base_set_size(&text1->base, 0.485f, 64);
djui_base_set_alignment(&text1->base, DJUI_HALIGN_LEFT, DJUI_VALIGN_TOP);
char starString[32] = { 0 };
snprintf(starString, 32, "%c x%d", '~' + 1, save_file_get_total_star_count(configHostSaveSlot - 1, 0, 24));
struct DjuiButton* button1 = djui_button_create(&rect2->base, starString);
djui_base_set_size_type(&button1->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
djui_base_set_size(&button1->base, 0.5f, 32);
djui_base_set_alignment(&button1->base, DJUI_HALIGN_RIGHT, DJUI_VALIGN_TOP);
djui_interactable_hook_click(&button1->base, djui_panel_host_save_create);
}
char* iChoices[3] = { "Non-solid", "Solid", "Friendly Fire" };
struct DjuiSelectionbox* selectionbox2 = djui_selectionbox_create(&body->base, "Player interaction", iChoices, 3, &configPlayerInteraction);
djui_base_set_size_type(&selectionbox2->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
djui_base_set_size(&selectionbox2->base, 1.0f, 32);
char* kChoices[3] = { "Weak", "Normal", "Too much" };
sKnockbackIndex = (configPlayerKnockbackStrength <= 20)
? 0
: ((configPlayerKnockbackStrength <= 40) ? 1 : 2);
struct DjuiSelectionbox* selectionbox3 = djui_selectionbox_create(&body->base, "Knockback strength", kChoices, 3, &sKnockbackIndex);
djui_base_set_size_type(&selectionbox3->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
djui_base_set_size(&selectionbox3->base, 1.0f, 32);
djui_interactable_hook_value_change(&selectionbox3->base, djui_panel_host_knockback_change);
struct DjuiCheckbox* checkbox1 = djui_checkbox_create(&body->base, "Stay in level after star", &configStayInLevelAfterStar);
djui_base_set_size_type(&checkbox1->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
djui_base_set_size(&checkbox1->base, 1.0f, 32);
struct DjuiCheckbox* checkbox2 = djui_checkbox_create(&body->base, "Play intro cutscene", &configSkipIntro);
djui_base_set_size_type(&checkbox2->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
djui_base_set_size(&checkbox2->base, 1.0f, 32);
struct DjuiCheckbox* checkbox3 = djui_checkbox_create(&body->base, "Share lives", &configShareLives);
djui_base_set_size_type(&checkbox3->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
djui_base_set_size(&checkbox3->base, 1.0f, 32);
struct DjuiCheckbox* checkbox4 = djui_checkbox_create(&body->base, "Enable cheats", &configEnableCheats);
djui_base_set_size_type(&checkbox4->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
djui_base_set_size(&checkbox4->base, 1.0f, 32);
struct DjuiRect* rect3 = djui_rect_create(&body->base);
djui_base_set_size_type(&rect3->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
djui_base_set_size(&rect3->base, 1.0f, 64);
djui_base_set_color(&rect3->base, 0, 0, 0, 0);
{
struct DjuiButton* button1 = djui_button_create(&rect3->base, "Back");
djui_base_set_size_type(&button1->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
djui_base_set_size(&button1->base, 0.485f, 64);
djui_base_set_alignment(&button1->base, DJUI_HALIGN_LEFT, DJUI_VALIGN_TOP);
djui_button_set_style(button1, 1);
djui_interactable_hook_click(&button1->base, djui_panel_menu_back);
struct DjuiButton* button2 = djui_button_create(&rect3->base, "Host");
djui_base_set_size_type(&button2->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
djui_base_set_size(&button2->base, 0.485f, 64);
djui_base_set_alignment(&button2->base, DJUI_HALIGN_RIGHT, DJUI_VALIGN_TOP);
djui_interactable_hook_click(&button2->base, djui_panel_host_do_host);
defaultBase = &button2->base;
}
}
djui_panel_add(caller, &panel->base, defaultBase);
}

View file

@ -0,0 +1,4 @@
#pragma once
#include "djui.h"
void djui_panel_host_create(struct DjuiBase* caller);

View file

@ -0,0 +1,109 @@
#include <stdio.h>
#include "djui.h"
#include "src/pc/network/network.h"
#include "src/pc/network/discord/discord.h"
#include "src/pc/utils/misc.h"
#include "src/pc/configfile.h"
#ifdef DISCORD_SDK
static char* sWarningDiscord = "\
Invite friends by right clicking their name on Discord and clicking on\n\
'\\#d0d0ff\\Invite to Game\\#c8c8c8\\'.\n\n\
You can invite channels of servers as well by clicking the \\#d0d0ff\\plus\\#c8c8c8\\ button next to the place where you enter chat.\n\n\
Game Activity \\#ffa0a0\\must be\\#c8c8c8\\ enabled in your\nDiscord user settings.\n\n\
Appearing offline \\#ffa0a0\\will prevent\\#c8c8c8\\ invites from being sent.\
";
static char* sWarningDiscord2 = "\\#ffa0a0\\Error:\\#c8c8c8\\ Could not detect Discord.\n\n\\#a0a0a0\\Try closing the game,\nrestarting Discord,\nand opening the game again.";
#endif
static char* sWarningSocket = "\
Direct connections \\#ffa0a0\\require you\\#c8c8c8\\ to configure port forwarding in your router.\n\n\
Forward port '\\#d0d0ff\\%d\\#c8c8c8\\' for UDP.\
";
void djui_panel_host_message_do_host(struct DjuiBase* caller) {
djui_panel_shutdown();
extern s16 gCurrSaveFileNum;
gCurrSaveFileNum = configHostSaveSlot;
#ifndef DISCORD_SDK
configNetworkSystem = 1;
network_set_system(NS_SOCKET);
#else
if (configNetworkSystem == 0) {
network_set_system(NS_DISCORD);
} else {
network_set_system(NS_SOCKET);
}
#endif
network_init(NT_SERVER);
extern s16 gChangeLevel;
gChangeLevel = 16;
}
void djui_panel_host_message_create(struct DjuiBase* caller) {
f32 warningLines = 0;
char* warningMessage = NULL;
bool hideHostButton = false;
#ifdef DISCORD_SDK
if (!configNetworkSystem) {
warningLines = gDiscordFailed ? 5 : 13;
warningMessage = gDiscordFailed ? sWarningDiscord2 : sWarningDiscord;
hideHostButton = gDiscordFailed;
} else
#endif
{
warningLines = 5;
warningMessage = malloc(sizeof(char) * 256);
sprintf(warningMessage, sWarningSocket, configHostPort);
}
f32 textHeight = 32 * 0.8125f * warningLines + 8;
f32 bodyHeight = textHeight + 16 + 64;
struct DjuiBase* defaultBase = NULL;
struct DjuiThreePanel* panel = djui_panel_menu_create(bodyHeight, "\\#ff0800\\I\\#1be700\\N\\#00b3ff\\F\\#ffef00\\O");
struct DjuiFlowLayout* body = (struct DjuiFlowLayout*)djui_three_panel_get_body(panel);
{
struct DjuiText* text1 = djui_text_create(&body->base, warningMessage);
djui_base_set_size_type(&text1->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
djui_base_set_size(&text1->base, 1.0f, textHeight);
djui_base_set_color(&text1->base, 200, 200, 200, 255);
struct DjuiRect* rect1 = djui_rect_create(&body->base);
djui_base_set_size_type(&rect1->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
djui_base_set_size(&rect1->base, 1.0f, 64);
djui_base_set_color(&rect1->base, 0, 0, 0, 0);
{
struct DjuiButton* button1 = djui_button_create(&rect1->base, "Back");
djui_base_set_size_type(&button1->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
djui_base_set_size(&button1->base, 0.485f, 64);
djui_base_set_alignment(&button1->base, DJUI_HALIGN_LEFT, DJUI_VALIGN_TOP);
djui_button_set_style(button1, 1);
djui_interactable_hook_click(&button1->base, djui_panel_menu_back);
struct DjuiButton* button2 = djui_button_create(&rect1->base, "Host");
djui_base_set_size_type(&button2->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
djui_base_set_size(&button2->base, 0.485f, 64);
djui_base_set_alignment(&button2->base, DJUI_HALIGN_RIGHT, DJUI_VALIGN_TOP);
djui_interactable_hook_click(&button2->base, djui_panel_host_message_do_host);
defaultBase = &button2->base;
if (hideHostButton) {
djui_base_set_size_type(&button1->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
djui_base_set_size(&button1->base, 1.0f, 64);
defaultBase = &button1->base;
djui_base_set_visible(&button2->base, false);
djui_base_set_enabled(&button2->base, false);
}
}
}
djui_panel_add(caller, &panel->base, defaultBase);
#ifdef DISCORD_SDK
if (configNetworkSystem)
#endif
{
free(warningMessage);
}
}

View file

@ -0,0 +1,4 @@
#pragma once
#include "djui.h"
void djui_panel_host_message_create(struct DjuiBase* caller);

View file

@ -0,0 +1,67 @@
#include <stdio.h>
#include "djui.h"
#include "game/save_file.h"
#include "pc/configfile.h"
static struct DjuiBase* sSaveButtonCaller = NULL;
static struct DjuiButton* sSaveButtons[4] = { NULL };
static void djui_panel_host_save_update_button(struct DjuiButton* button, int slot) {
char starString[32] = { 0 };
snprintf(starString, 32, "%c x%d", '~' + 1, save_file_get_total_star_count(slot, 0, 24));
djui_text_set_text(button->text, starString);
}
static void djui_panel_host_save_button_click(struct DjuiBase* caller) {
configHostSaveSlot = caller->tag + 1;
djui_panel_host_save_update_button((struct DjuiButton*)sSaveButtonCaller, configHostSaveSlot - 1);
djui_panel_menu_back(caller);
}
static void djui_panel_host_save_erase_yes(struct DjuiBase* caller) {
save_file_erase(caller->tag);
djui_panel_host_save_update_button(sSaveButtons[caller->tag], caller->tag);
djui_panel_menu_back(caller);
}
static void djui_panel_host_save_erase(struct DjuiBase* caller) {
djui_panel_confirm_create(caller,
"\\#ff0800\\E\\#1be700\\R\\#00b3ff\\A\\#ffef00\\S\\#ff0800\\E",
"Are you sure you want to erase this save slot?",
djui_panel_host_save_erase_yes);
}
void djui_panel_host_save_create(struct DjuiBase* caller) {
f32 bodyHeight = 32 * 4 + 64 * 1 + 16 * 5;
sSaveButtonCaller = caller;
struct DjuiBase* defaultBase = NULL;
struct DjuiThreePanel* panel = djui_panel_menu_create(bodyHeight, "\\#ff0800\\S\\#1be700\\A\\#00b3ff\\V\\#ffef00\\E");
struct DjuiFlowLayout* body = (struct DjuiFlowLayout*)djui_three_panel_get_body(panel);
{
for (int i = 0; i < 4; i++) {
struct DjuiRect* rect1 = djui_rect_create(&body->base);
djui_base_set_size_type(&rect1->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
djui_base_set_size(&rect1->base, 1.0f, 32);
djui_base_set_color(&rect1->base, 0, 0, 0, 0);
{
struct DjuiButton* button1 = djui_button_create(&rect1->base, "");
djui_panel_host_save_update_button(button1, i);
djui_base_set_size_type(&button1->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
djui_base_set_size(&button1->base, 0.74f, 32);
djui_interactable_hook_click(&button1->base, djui_panel_host_save_button_click);
button1->base.tag = i;
if (i == (int)(configHostSaveSlot - 1)) { defaultBase = &button1->base; }
sSaveButtons[i] = button1;
struct DjuiButton* button2 = djui_button_create(&rect1->base, "erase");
djui_base_set_size_type(&button2->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
djui_base_set_size(&button2->base, 0.24f, 32);
djui_base_set_alignment(&button2->base, DJUI_HALIGN_RIGHT, DJUI_VALIGN_TOP);
djui_interactable_hook_click(&button2->base, djui_panel_host_save_erase);
}
}
}
djui_panel_add(caller, &panel->base, defaultBase);
}

View file

@ -0,0 +1,4 @@
#pragma once
#include "djui.h"
void djui_panel_host_save_create(struct DjuiBase* caller);

View file

@ -0,0 +1,212 @@
#include <stdio.h>
#include "djui.h"
#include "src/pc/network/network.h"
#include "src/pc/utils/misc.h"
#include "src/pc/configfile.h"
#ifdef DISCORD_SDK
static char* sJoiningDiscord = "\
To join a \\#d0d0ff\\Discord\\#c8c8c8\\ lobby:\n\n\
Keep the game open and click the join button on the invite.\n\n\
If the invite says that the game has ended, click the name of the person that sent the invite to refresh it.\
";
#endif
static char* sJoiningDirect = "\
Enter \\#d0d0ff\\direct connection\\#c8c8c8\\ IP and port:\
";
static struct DjuiInputbox* sInputboxIp = NULL;
static bool djui_panel_join_ip_parse_numbers(char** msg) {
int num = 0;
for (int i = 0; i < 3; i++) {
char c = **msg;
if (c >= '0' && c <= '9') {
// is number
num *= 10;
num += (c - '0');
*msg = *msg + 1;
} else if (i == 0) {
return false;
} else {
break;
}
}
return num >= 0 && num <= 127;
}
static bool djui_panel_join_ip_parse_period(char** msg) {
char c = **msg;
bool isPeriod = (c == '.');
if (isPeriod) { *msg = *msg + 1; }
return isPeriod;
}
static bool djui_panel_join_ip_parse_spacer(char** msg) {
char c = **msg;
bool isSpacer = (c == ':' || c == ' ');
if (isSpacer) { *msg = *msg + 1; }
return isSpacer;
}
static bool djui_panel_join_ip_parse_port(char** msg) {
int num = 0;
for (int i = 0; i < 5; i++) {
char c = **msg;
if (c >= '0' && c <= '9') {
// is number
num *= 10;
num += (c - '0');
*msg = *msg + 1;
} else if (i == 0) {
return false;
} else {
break;
}
}
return num >= 1024 && num <= 65535;
}
static bool djui_panel_join_ip_valid(char* buffer) {
char** msg = &buffer;
if (!djui_panel_join_ip_parse_numbers(msg)) { return false; }
if (!djui_panel_join_ip_parse_period(msg)) { return false; }
if (!djui_panel_join_ip_parse_numbers(msg)) { return false; }
if (!djui_panel_join_ip_parse_period(msg)) { return false; }
if (!djui_panel_join_ip_parse_numbers(msg)) { return false; }
if (!djui_panel_join_ip_parse_period(msg)) { return false; }
if (!djui_panel_join_ip_parse_numbers(msg)) { return false; }
if (djui_panel_join_ip_parse_spacer(msg)) {
if (!djui_panel_join_ip_parse_port(msg)) { return false; }
}
return (**msg == '\0');
}
static void djui_panel_join_ip_text_change(struct DjuiBase* caller) {
struct DjuiInputbox* inputbox1 = (struct DjuiInputbox*)caller;
if (djui_panel_join_ip_valid(inputbox1->buffer)) {
djui_inputbox_set_text_color(inputbox1, 0, 0, 0, 255);
} else {
djui_inputbox_set_text_color(inputbox1, 255, 0, 0, 255);
}
}
static void djui_panel_join_ip_text_set_new(void) {
char buffer[256] = { 0 };
snprintf(buffer, 256, "%s", sInputboxIp->buffer);
bool afterSpacer = false;
int port = 0;
for (int i = 0; i < 256; i++) {
if (buffer[i] == ' ' || buffer[i] == ':') {
buffer[i] = '\0';
afterSpacer = true;
} else if (buffer[i] == '\0') {
break;
} else if (afterSpacer && buffer[i] >= '0' && buffer[i] <= '9') {
port *= 10;
port += buffer[i] - '0';
}
}
snprintf(configJoinIp, MAX_CONFIG_STRING, "%s", buffer);
if (port >= 1 && port <= 65535) {
configJoinPort = port;
} else {
configJoinPort = DEFAULT_PORT;
}
}
static void djui_panel_join_ip_text_set(struct DjuiInputbox* inputbox1) {
char buffer[256] = { 0 };
if (strlen(configJoinIp) > 0 && configJoinPort != DEFAULT_PORT) {
snprintf(buffer, 256, "%s:%d", configJoinIp, configJoinPort);
} else if (strlen(configJoinIp) > 0) {
snprintf(buffer, 256, "%s", configJoinIp);
} else {
snprintf(buffer, 256, "127.0.0.1");
}
djui_inputbox_set_text(inputbox1, buffer);
djui_inputbox_select_all(inputbox1);
}
void djui_panel_join_do_join(struct DjuiBase* caller) {
if (!djui_panel_join_ip_valid(sInputboxIp->buffer)) {
djui_interactable_set_input_focus(&sInputboxIp->base);
djui_inputbox_select_all(sInputboxIp);
return;
}
djui_panel_join_ip_text_set_new();
network_set_system(NS_SOCKET);
network_init(NT_CLIENT);
djui_panel_join_message_create(caller);
}
void djui_panel_join_create(struct DjuiBase* caller) {
f32 bodyHeight = 2 + 32 + 16 * 2 + 64;
u16 directLines = 1;
f32 directTextHeight = 32 * 0.8125f * directLines + 8;
bodyHeight += directTextHeight + 16;
#ifdef DISCORD_SDK
u16 discordLines = 8;
f32 discordTextHeight = 32 * 0.8125f * discordLines + 8;
bodyHeight += discordTextHeight + 16;
#endif
struct DjuiBase* defaultBase = NULL;
struct DjuiThreePanel* panel = djui_panel_menu_create(bodyHeight, "\\#ff0800\\J\\#1be700\\O\\#00b3ff\\I\\#ffef00\\N");
struct DjuiFlowLayout* body = (struct DjuiFlowLayout*)djui_three_panel_get_body(panel);
{
#ifdef DISCORD_SDK
struct DjuiText* text1 = djui_text_create(&body->base, sJoiningDiscord);
djui_base_set_size_type(&text1->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
djui_base_set_size(&text1->base, 1.0f, discordTextHeight);
djui_base_set_color(&text1->base, 200, 200, 200, 255);
#endif
struct DjuiRect* rect1 = djui_rect_create(&body->base);
djui_base_set_size_type(&rect1->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
djui_base_set_size(&rect1->base, 1.0f, 2);
djui_base_set_color(&rect1->base, 150, 150, 150, 255);
struct DjuiText* text2 = djui_text_create(&body->base, sJoiningDirect);
djui_base_set_size_type(&text2->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
djui_base_set_size(&text2->base, 1.0f, directTextHeight);
djui_base_set_color(&text2->base, 200, 200, 200, 255);
struct DjuiInputbox* inputbox1 = djui_inputbox_create(&body->base, 256);
djui_base_set_size_type(&inputbox1->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
djui_base_set_size(&inputbox1->base, 1.0f, 32.0f);
djui_interactable_hook_value_change(&inputbox1->base, djui_panel_join_ip_text_change);
sInputboxIp = inputbox1;
djui_panel_join_ip_text_set(inputbox1);
struct DjuiRect* rect2 = djui_rect_create(&body->base);
djui_base_set_size_type(&rect2->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
djui_base_set_size(&rect2->base, 1.0f, 64);
djui_base_set_color(&rect2->base, 0, 0, 0, 0);
{
struct DjuiButton* button1 = djui_button_create(&rect2->base, "Back");
djui_base_set_size_type(&button1->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
djui_base_set_size(&button1->base, 0.485f, 64);
djui_base_set_alignment(&button1->base, DJUI_HALIGN_LEFT, DJUI_VALIGN_TOP);
djui_button_set_style(button1, 1);
djui_interactable_hook_click(&button1->base, djui_panel_menu_back);
struct DjuiButton* button2 = djui_button_create(&rect2->base, "Join");
djui_base_set_size_type(&button2->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
djui_base_set_size(&button2->base, 0.485f, 64);
djui_base_set_alignment(&button2->base, DJUI_HALIGN_RIGHT, DJUI_VALIGN_TOP);
djui_interactable_hook_click(&button2->base, djui_panel_join_do_join);
defaultBase = &button2->base;
}
}
djui_panel_add(caller, &panel->base, defaultBase);
}

View file

@ -0,0 +1,4 @@
#pragma once
#include "djui.h"
void djui_panel_join_create(struct DjuiBase* caller);

View file

@ -0,0 +1,75 @@
#include "djui.h"
#include "src/pc/network/network.h"
#include "src/pc/utils/misc.h"
#include "src/pc/configfile.h"
#define DJUI_JOIN_MESSAGE_ELAPSE 60
bool gDjuiPanelJoinMessageVisible = false;
static struct DjuiText* sPanelText = NULL;
static bool sDisplayingError = false;
void djui_panel_join_message_error(char* message) {
djui_panel_join_message_create(NULL);
sDisplayingError = true;
djui_text_set_text(sPanelText, message);
}
void djui_panel_join_message_cancel(struct DjuiBase* caller) {
network_shutdown(true);
djui_panel_menu_back(caller);
}
void djui_panel_join_message_render_pre(struct DjuiBase* base, UNUSED bool* unused) {
if (sDisplayingError) { return; }
struct DjuiText* text1 = (struct DjuiText*)base;
u16 lastElapse = (base->tag / DJUI_JOIN_MESSAGE_ELAPSE);
base->tag = (base->tag + 1) % (DJUI_JOIN_MESSAGE_ELAPSE * 3);
u16 elapse = (base->tag / DJUI_JOIN_MESSAGE_ELAPSE);
if (lastElapse != elapse) {
switch (base->tag / DJUI_JOIN_MESSAGE_ELAPSE) {
case 0: djui_text_set_text(text1, "..."); break;
case 1: djui_text_set_text(text1, "."); break;
default: djui_text_set_text(text1, ".."); break;
}
}
}
void djui_panel_join_message_create(struct DjuiBase* caller) {
// make sure main panel was created
if (!gDjuiPanelMainCreated) { djui_panel_main_create(caller); }
// don't recreate panel if it's already visible
if (gDjuiPanelJoinMessageVisible) { return; }
f32 bodyHeight = 64 + 16;
u16 directLines = 8;
f32 directTextHeight = 32 * 0.8125f * directLines + 8;
bodyHeight += directTextHeight + 16;
struct DjuiBase* defaultBase = NULL;
struct DjuiThreePanel* panel = djui_panel_menu_create(bodyHeight, "\\#ff0800\\J\\#1be700\\O\\#00b3ff\\I\\#ffef00\\N\\#1be700\\I\\#00b3ff\\N\\#ffef00\\G");
struct DjuiFlowLayout* body = (struct DjuiFlowLayout*)djui_three_panel_get_body(panel);
{
struct DjuiText* text1 = djui_text_create(&body->base, "...");
djui_base_set_size_type(&text1->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
djui_base_set_size(&text1->base, 1.0f, directTextHeight);
djui_base_set_color(&text1->base, 200, 200, 200, 255);
djui_text_set_alignment(text1, DJUI_HALIGN_CENTER, DJUI_VALIGN_CENTER);
text1->base.tag = 0;
text1->base.on_render_pre = djui_panel_join_message_render_pre;
sPanelText = text1;
struct DjuiButton* button1 = djui_button_create(&body->base, "Cancel");
djui_base_set_size_type(&button1->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
djui_base_set_size(&button1->base, 1.0f, 64);
djui_base_set_alignment(&button1->base, DJUI_HALIGN_LEFT, DJUI_VALIGN_TOP);
djui_button_set_style(button1, 1);
djui_interactable_hook_click(&button1->base, djui_panel_join_message_cancel);
defaultBase = &button1->base;
}
djui_panel_add(caller, &panel->base, defaultBase);
gDjuiPanelJoinMessageVisible = true;
sDisplayingError = false;
}

View file

@ -0,0 +1,7 @@
#pragma once
#include "djui.h"
extern bool gDjuiPanelJoinMessageVisible;
void djui_panel_join_message_error(char* message);
void djui_panel_join_message_create(struct DjuiBase* caller);

View file

@ -0,0 +1,60 @@
#include "djui.h"
#include "src/pc/controller/controller_sdl.h"
bool gDjuiPanelMainCreated = false;
static void djui_panel_main_quit_yes(struct DjuiBase* caller) {
exit(0);
}
static void djui_panel_main_quit(struct DjuiBase* caller) {
djui_panel_confirm_create(caller,
"\\#ff0800\\Q\\#1be700\\U\\#00b3ff\\I\\#ffef00\\T",
"Are you sure you want to quit?",
djui_panel_main_quit_yes);
}
void djui_panel_main_create(struct DjuiBase* caller) {
f32 bodyHeight = 64 * 4 + 16 * 3;
struct DjuiBase* defaultBase = NULL;
struct DjuiThreePanel* panel = djui_panel_menu_create(bodyHeight, "\\#ff0800\\SM\\#1be700\\64\\#00b3ff\\EX\n\\#ffef00\\COOP");
{
struct DjuiFlowLayout* body = (struct DjuiFlowLayout*)djui_three_panel_get_body(panel);
{
struct DjuiButton* button1 = djui_button_create(&body->base, "Host");
djui_base_set_size_type(&button1->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
djui_base_set_size(&button1->base, 1.0f, 64);
djui_cursor_input_controlled_center(&button1->base);
djui_interactable_hook_click(&button1->base, djui_panel_host_create);
defaultBase = &button1->base;
struct DjuiButton* button2 = djui_button_create(&body->base, "Join");
djui_base_set_size_type(&button2->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
djui_base_set_size(&button2->base, 1.0f, 64);
djui_interactable_hook_click(&button2->base, djui_panel_join_create);
struct DjuiButton* button3 = djui_button_create(&body->base, "Options");
djui_base_set_size_type(&button3->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
djui_base_set_size(&button3->base, 1.0f, 64);
djui_interactable_hook_click(&button3->base, djui_panel_options_create);
struct DjuiButton* button4 = djui_button_create(&body->base, "Quit");
djui_base_set_size_type(&button4->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
djui_base_set_size(&button4->base, 1.0f, 64);
djui_button_set_style(button4, 1);
djui_interactable_hook_click(&button4->base, djui_panel_main_quit);
}
char* version = get_version();
struct DjuiText* footer = djui_text_create(&panel->base, version);
djui_base_set_size_type(&footer->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
djui_base_set_size(&footer->base, 1.0f, 1.0f);
djui_base_set_color(&footer->base, 50, 50, 50, 255);
djui_text_set_alignment(footer, DJUI_HALIGN_CENTER, DJUI_VALIGN_BOTTOM);
}
djui_panel_add(caller, &panel->base, defaultBase);
gInteractableOverridePad = true;
gDjuiPanelMainCreated = true;
}

View file

@ -0,0 +1,6 @@
#pragma once
#include "djui.h"
extern bool gDjuiPanelMainCreated;
void djui_panel_main_create(struct DjuiBase* caller);

View file

@ -0,0 +1,36 @@
#include "djui.h"
#include "src/pc/utils/misc.h"
#include "src/pc/configfile.h"
void djui_panel_menu_back(struct DjuiBase* base) {
djui_panel_back();
}
struct DjuiThreePanel* djui_panel_menu_create(f32 bodyHeight, char* headerText) {
struct DjuiThreePanel* panel = djui_three_panel_create(&gDjuiRoot->base, 64, bodyHeight, 0);
djui_base_set_size_type(&panel->base, DJUI_SVT_ABSOLUTE, DJUI_SVT_RELATIVE);
djui_base_set_size(&panel->base, DJUI_DEFAULT_PANEL_WIDTH, 1.0f);
djui_base_set_color(&panel->base, 0, 0, 0, 240);
djui_base_set_border_color(&panel->base, 0, 0, 0, 200);
djui_base_set_border_width(&panel->base, 8);
djui_base_set_padding(&panel->base, 16, 16, 16, 16);
{
struct DjuiText* header = djui_text_create(&panel->base, headerText);
djui_base_set_size_type(&header->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
djui_base_set_size(&header->base, 1.0f, 1.0f);
djui_base_set_color(&header->base, 255, 8, 0, 255);
djui_base_set_location(&header->base, 0, DJUI_PANEL_HEADER_OFFSET);
djui_text_set_alignment(header, DJUI_HALIGN_CENTER, DJUI_VALIGN_BOTTOM);
djui_text_set_font(header, &gDjuiFonts[1]);
djui_text_set_font_scale(header, gDjuiFonts[1].defaultFontScale);
struct DjuiFlowLayout* body = djui_flow_layout_create(&panel->base);
djui_base_set_alignment(&body->base, DJUI_HALIGN_CENTER, DJUI_VALIGN_CENTER);
djui_base_set_size_type(&body->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
djui_base_set_size(&body->base, 1.0f, bodyHeight);
djui_base_set_color(&body->base, 0, 0, 0, 0);
djui_flow_layout_set_margin(body, 16);
djui_flow_layout_set_flow_direction(body, DJUI_FLOW_DIR_DOWN);
}
return panel;
}

View file

@ -0,0 +1,5 @@
#pragma once
#include "djui.h"
void djui_panel_menu_back(struct DjuiBase* base);
struct DjuiThreePanel* djui_panel_menu_create(f32 bodyHeight, char* headerText);

View file

@ -0,0 +1,45 @@
#include "djui.h"
#include "src/pc/utils/misc.h"
void djui_panel_options_create(struct DjuiBase* caller) {
f32 bodyHeight = 64 * 5 + 16 * 4;
struct DjuiBase* defaultBase = NULL;
struct DjuiThreePanel* panel = djui_panel_menu_create(bodyHeight, "\\#ff0800\\O\\#1be700\\P\\#00b3ff\\T\\#ffef00\\I\\#ff0800\\O\\#1be700\\N\\#00b3ff\\S");
struct DjuiFlowLayout* body = (struct DjuiFlowLayout*)djui_three_panel_get_body(panel);
{
/*struct DjuiButton* button1 = djui_button_create(&body->base, "Player");
djui_base_set_size_type(&button1->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
djui_base_set_size(&button1->base, 1.0f, 64);
defaultBase = &button1->base;*/
struct DjuiButton* button2 = djui_button_create(&body->base, "Camera");
djui_base_set_size_type(&button2->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
djui_base_set_size(&button2->base, 1.0f, 64);
djui_interactable_hook_click(&button2->base, djui_panel_camera_create);
defaultBase = &button2->base;
struct DjuiButton* button3 = djui_button_create(&body->base, "Controls");
djui_base_set_size_type(&button3->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
djui_base_set_size(&button3->base, 1.0f, 64);
djui_interactable_hook_click(&button3->base, djui_panel_controls_create);
struct DjuiButton* button4 = djui_button_create(&body->base, "Display");
djui_base_set_size_type(&button4->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
djui_base_set_size(&button4->base, 1.0f, 64);
djui_interactable_hook_click(&button4->base, djui_panel_display_create);
struct DjuiButton* button5 = djui_button_create(&body->base, "Sound");
djui_base_set_size_type(&button5->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
djui_base_set_size(&button5->base, 1.0f, 64);
djui_interactable_hook_click(&button5->base, djui_panel_sound_create);
struct DjuiButton* button6 = djui_button_create(&body->base, "Back");
djui_base_set_size_type(&button6->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
djui_base_set_size(&button6->base, 1.0f, 64);
djui_button_set_style(button6, 1);
djui_interactable_hook_click(&button6->base, djui_panel_menu_back);
}
djui_panel_add(caller, &panel->base, defaultBase);
}

View file

@ -0,0 +1,4 @@
#pragma once
#include "djui.h"
void djui_panel_options_create(struct DjuiBase* caller);

Some files were not shown because too many files have changed in this diff Show more