mirror of
https://github.com/zeldaret/tww.git
synced 2026-07-08 21:54:50 -04:00
d_mesg
This commit is contained in:
+1
-1
@@ -567,7 +567,7 @@ config.libs = [
|
||||
Object(NonMatching, "d/d_menu_option.cpp"),
|
||||
Object(NonMatching, "d/d_menu_save.cpp"),
|
||||
Object(NonMatching, "d/d_menu_window.cpp"),
|
||||
Object(NonMatching, "d/d_mesg.cpp"),
|
||||
Object(NonMatching, "d/d_mesg.cpp", extra_cflags=["-sym off"]),
|
||||
Object(NonMatching, "d/d_message.cpp"),
|
||||
Object(NonMatching, "d/d_message_paper.cpp"),
|
||||
Object(NonMatching, "d/d_meter.cpp"),
|
||||
|
||||
@@ -96,7 +96,9 @@ public:
|
||||
setBlendColorRatio(f1, f2, f3, f4);
|
||||
setBlendAlphaRatio(f1, f2, f3, f4);
|
||||
}
|
||||
const JUtility::TColor& getWhite() const { return mColorWhite; }
|
||||
bool setWhite(JUtility::TColor white) { mColorWhite = white; return true; }
|
||||
const JUtility::TColor& getBlack() const { return mColorBlack; }
|
||||
bool setBlack(JUtility::TColor black) { mColorBlack = black; return true; }
|
||||
bool setBlackWhite(JUtility::TColor black, JUtility::TColor white) {
|
||||
mColorBlack = black;
|
||||
@@ -121,9 +123,7 @@ public:
|
||||
void load(u8 i) { mpTexture[i]->load((GXTexMapID)i); }
|
||||
|
||||
// TODO
|
||||
void getBlack() const {}
|
||||
void getCornerColor(J2DPicture::TCornerColor&) const {}
|
||||
void getWhite() const {}
|
||||
|
||||
protected:
|
||||
/* 0x0CC */ JUTTexture* mpTexture[4];
|
||||
|
||||
@@ -68,7 +68,7 @@ public:
|
||||
virtual void resize(f32, f32);
|
||||
virtual u16 getTypeID() { return 19; };
|
||||
|
||||
private:
|
||||
public:
|
||||
/* 0xCC */ JUTFont* mpFont;
|
||||
/* 0xD0 */ JUtility::TColor mCharColor;
|
||||
/* 0xD4 */ JUtility::TColor mGradColor;
|
||||
|
||||
@@ -60,7 +60,7 @@ public:
|
||||
virtual void do_select_separate();
|
||||
virtual void do_begin_(const void*, const char*) = 0;
|
||||
virtual void do_end_() = 0;
|
||||
virtual bool do_tag_(u32, const void*, u32) = 0;
|
||||
virtual void do_tag_(u32, const void*, u32) = 0;
|
||||
virtual void do_systemTagCode_(u16, const void*, u32) = 0;
|
||||
|
||||
void setBegin_messageCode(u16, u16);
|
||||
@@ -123,7 +123,7 @@ struct TSequenceProcessor : public TProcessor {
|
||||
/* 0x08 */ virtual ~TSequenceProcessor();
|
||||
/* 0x30 */ virtual void do_begin_(const void*, const char*);
|
||||
/* 0x34 */ virtual void do_end_();
|
||||
/* 0x38 */ virtual bool do_tag_(u32, const void*, u32);
|
||||
/* 0x38 */ virtual void do_tag_(u32, const void*, u32);
|
||||
/* 0x3C */ virtual void do_systemTagCode_(u16, const void*, u32);
|
||||
/* 0x40 */ virtual void do_begin(const void*, const char*);
|
||||
/* 0x44 */ virtual void do_end();
|
||||
@@ -186,7 +186,7 @@ struct TRenderingProcessor : public TProcessor {
|
||||
|
||||
virtual void do_begin_(const void*, const char*);
|
||||
virtual void do_end_();
|
||||
virtual bool do_tag_(u32, const void*, u32);
|
||||
virtual void do_tag_(u32, const void*, u32);
|
||||
virtual void do_systemTagCode_(u16, const void*, u32);
|
||||
virtual ~TRenderingProcessor();
|
||||
virtual void do_begin(const void*, const char*);
|
||||
|
||||
+171
-66
@@ -3,23 +3,50 @@
|
||||
|
||||
#include "dolphin/types.h"
|
||||
#include "JSystem/JMessage/control.h"
|
||||
#include "d/d_drawlist.h"
|
||||
#include "f_op/f_op_msg.h"
|
||||
#include "f_op/f_op_msg_mng.h"
|
||||
|
||||
class JUTFont;
|
||||
class J2DPicture;
|
||||
class J2DScreen;
|
||||
class JKRExpHeap;
|
||||
class JUTFont;
|
||||
class JPABaseEmitter;
|
||||
class dMesg_outFont_c;
|
||||
class dMesg_screenData_c;
|
||||
|
||||
class sub_mesg_class;
|
||||
class sub_mesg_class : public msg_class {
|
||||
public:
|
||||
/* 0x0FC */ JKRExpHeap* heap;
|
||||
/* 0x100 */ JKRExpHeap* field_0x100;
|
||||
/* 0x104 */ dMesg_outFont_c* outfont[18];
|
||||
/* 0x14C */ dMesg_screenData_c* screen;
|
||||
/* 0x150 */ u8 field_0x150[0x154 - 0x150];
|
||||
/* 0x154 */ char* text[4];
|
||||
/* 0x164 */ u8 field_0x164;
|
||||
};
|
||||
|
||||
class dMesg_outFont_c {
|
||||
public:
|
||||
void getTimer() {}
|
||||
|
||||
~dMesg_outFont_c();
|
||||
|
||||
virtual ~dMesg_outFont_c();
|
||||
void _create();
|
||||
void _delete();
|
||||
void _initialize();
|
||||
void _set(s16, s16, s16, u32, u8);
|
||||
bool _set(s16, s16, s16, u32, u8);
|
||||
void _draw();
|
||||
void _setAlpha(u8);
|
||||
|
||||
/* 0x04 */ J2DPicture* icon;
|
||||
/* 0x08 */ J2DPicture* kage;
|
||||
/* 0x0C */ int field_0xc;
|
||||
/* 0x10 */ s16 field_0x10;
|
||||
/* 0x12 */ s16 field_0x12;
|
||||
/* 0x14 */ s16 field_0x14;
|
||||
/* 0x16 */ s16 field_0x16;
|
||||
/* 0x18 */ u8 mAlpha;
|
||||
/* 0x19 */ u8 field_0x19;
|
||||
};
|
||||
|
||||
class dMesg_tControl : public JMessage::TControl {
|
||||
@@ -42,78 +69,136 @@ public:
|
||||
void setLineCount(int) {}
|
||||
void setLineLength(int, f32) {}
|
||||
void setLineStart(int) {}
|
||||
void setMainFont(JUTFont*) {}
|
||||
void setMainFont(JUTFont* font) { mMainFont = font; }
|
||||
void setNowFontSize(int) {}
|
||||
void setRubyFont(JUTFont*) {}
|
||||
|
||||
void setRubyFont(JUTFont* font) { mRubyFont = font; }
|
||||
|
||||
dMesg_tControl();
|
||||
const char* do_word(u32);
|
||||
|
||||
public:
|
||||
/* 0x3C */ u8 field_0x3C[0x74 - 0x3C];
|
||||
/* 0x3C */ JUTFont* mMainFont;
|
||||
/* 0x40 */ JUTFont* mRubyFont;
|
||||
/* 0x44 */ f32 field_0x44[4];
|
||||
/* 0x54 */ int field_0x54;
|
||||
/* 0x58 */ int field_0x58;
|
||||
/* 0x5C */ int field_0x5c;
|
||||
/* 0x60 */ int field_0x60;
|
||||
/* 0x64 */ int field_0x64;
|
||||
/* 0x68 */ int field_0x68;
|
||||
/* 0x6C */ int field_0x6c;
|
||||
/* 0x70 */ u8 field_0x70;
|
||||
/* 0x71 */ u8 field_0x71;
|
||||
};
|
||||
|
||||
class dMesg_tSequenceProcessor {
|
||||
class dMesg_tSequenceProcessor : public JMessage::TSequenceProcessor {
|
||||
public:
|
||||
void decWaitRest() {}
|
||||
void getNowColor() {}
|
||||
void getStopFlag() {}
|
||||
void resetWaitRest() {}
|
||||
void setMesg(sub_mesg_class*) {}
|
||||
void setMesg(sub_mesg_class* mesg) { mMesg = mesg; }
|
||||
void setNowColor(u32) {}
|
||||
void setShortCutFlag() {}
|
||||
void setWaitRest() {}
|
||||
|
||||
|
||||
dMesg_tSequenceProcessor(JMessage::TControl*);
|
||||
~dMesg_tSequenceProcessor();
|
||||
virtual ~dMesg_tSequenceProcessor() {}
|
||||
void initialize(int);
|
||||
void do_begin(const void*, const char*);
|
||||
void do_end();
|
||||
void do_isReady();
|
||||
void do_jump_isReady();
|
||||
void do_jump(const void*, const char*);
|
||||
void do_branch_query(u16);
|
||||
void do_branch_queryResult();
|
||||
void do_branch(const void*, const char*);
|
||||
void do_character(int);
|
||||
void do_tag(u32, const void*, u32);
|
||||
virtual void do_begin(const void*, const char*);
|
||||
virtual void do_end();
|
||||
virtual bool do_isReady();
|
||||
virtual bool do_jump_isReady();
|
||||
virtual void do_jump(const void*, const char*);
|
||||
virtual void do_branch_query(u16);
|
||||
virtual int do_branch_queryResult();
|
||||
virtual void do_branch(const void*, const char*);
|
||||
virtual void do_character(int);
|
||||
virtual bool do_tag(u32, const void*, u32);
|
||||
void setCharacter();
|
||||
void ruby_character(char*, int);
|
||||
void do_systemTagCode(u16, const void*, u32);
|
||||
char* ruby_character(char*, int);
|
||||
virtual bool do_systemTagCode(u16, const void*, u32);
|
||||
|
||||
/* 0x038 */ sub_mesg_class* mMesg;
|
||||
/* 0x03C */ const void* field_0x3c;
|
||||
/* 0x040 */ const char* field_0x40;
|
||||
/* 0x044 */ f32 field_0x44;
|
||||
/* 0x048 */ f32 field_0x48;
|
||||
/* 0x04C */ f32 field_0x4c;
|
||||
/* 0x050 */ f32 field_0x50;
|
||||
/* 0x054 */ f32 field_0x54;
|
||||
/* 0x058 */ int field_0x58;
|
||||
/* 0x05C */ int field_0x5c;
|
||||
/* 0x060 */ int field_0x60;
|
||||
/* 0x064 */ int field_0x64;
|
||||
/* 0x068 */ int field_0x68;
|
||||
/* 0x06C */ u32 field_0x6c;
|
||||
/* 0x070 */ int field_0x70;
|
||||
/* 0x074 */ int field_0x74;
|
||||
/* 0x078 */ int field_0x78;
|
||||
/* 0x07C */ int field_0x7c[4];
|
||||
/* 0x08C */ int field_0x8c;
|
||||
/* 0x090 */ int field_0x90;
|
||||
/* 0x094 */ char field_0x94;
|
||||
/* 0x095 */ u8 field_0x95;
|
||||
/* 0x096 */ u8 field_0x96;
|
||||
/* 0x097 */ char field_0x97[100];
|
||||
/* 0x0FB */ char field_0xfb[100];
|
||||
/* 0x15F */ u8 field_0x15f;
|
||||
/* 0x160 */ u8 field_0x160;
|
||||
/* 0x161 */ u8 field_0x161;
|
||||
/* 0x162 */ u8 field_0x162;
|
||||
/* 0x163 */ u8 field_0x163;
|
||||
};
|
||||
|
||||
class dMesg_tMeasureProcessor {
|
||||
class dMesg_tMeasureProcessor : public JMessage::TSequenceProcessor {
|
||||
public:
|
||||
dMesg_tMeasureProcessor(JMessage::TControl*, int);
|
||||
~dMesg_tMeasureProcessor();
|
||||
void do_character(int);
|
||||
void do_end();
|
||||
void do_tag(u32, const void*, u32);
|
||||
void do_systemTagCode(u16, const void*, u32);
|
||||
virtual ~dMesg_tMeasureProcessor() {}
|
||||
virtual void do_character(int);
|
||||
virtual void do_end();
|
||||
virtual bool do_tag(u32, const void*, u32);
|
||||
virtual bool do_systemTagCode(u16, const void*, u32);
|
||||
|
||||
/* 0x38 */ f32 field_0x38[4];
|
||||
/* 0x48 */ f32 field_0x48;
|
||||
/* 0x4C */ int field_0x4c;
|
||||
/* 0x50 */ int field_0x50;
|
||||
/* 0x54 */ u8 field_0x54;
|
||||
};
|
||||
|
||||
class dMesg_tRenderingProcessor {
|
||||
class dMesg_tRenderingProcessor : public JMessage::TRenderingProcessor {
|
||||
public:
|
||||
dMesg_tRenderingProcessor(JMessage::TControl*);
|
||||
~dMesg_tRenderingProcessor();
|
||||
void do_begin(const void*, const char*);
|
||||
void do_end();
|
||||
void do_character(int);
|
||||
void do_tag(u32, const void*, u32);
|
||||
void do_systemTagCode(u16, const void*, u32);
|
||||
virtual ~dMesg_tRenderingProcessor() {}
|
||||
virtual void do_begin(const void*, const char*);
|
||||
virtual void do_end();
|
||||
virtual void do_character(int);
|
||||
virtual bool do_tag(u32, const void*, u32);
|
||||
virtual bool do_systemTagCode(u16, const void*, u32);
|
||||
};
|
||||
|
||||
class dMesg_screenData_c {
|
||||
class dMesg_screenData_c : public dDlst_base_c {
|
||||
public:
|
||||
void deleteScreen() {}
|
||||
void getTextPosX(int) {}
|
||||
void getTextPosY(int) {}
|
||||
void resetTimer() {}
|
||||
void setFont(JUTFont*, JUTFont*) {}
|
||||
void setHeap(JKRExpHeap*) {}
|
||||
void setMesg(sub_mesg_class*) {}
|
||||
|
||||
~dMesg_screenData_c();
|
||||
void setFont(JUTFont* font1, JUTFont* font2) {
|
||||
field_0x10 = font1;
|
||||
field_0x14 = font2;
|
||||
}
|
||||
void setHeap(JKRExpHeap* heap) { mHeap = heap; }
|
||||
void setMesg(sub_mesg_class* mesg) { mMesg = mesg; }
|
||||
|
||||
virtual ~dMesg_screenData_c() {}
|
||||
virtual void draw() {}
|
||||
virtual void createScreen() {}
|
||||
virtual void changeFont(JUTFont*) {}
|
||||
virtual void move() {}
|
||||
virtual bool openAnime() = 0;
|
||||
virtual bool closeAnime() = 0;
|
||||
virtual void setTextPosition(u8) {}
|
||||
void setCommonData();
|
||||
void initString(char*, int);
|
||||
void setString(char*, int);
|
||||
@@ -122,37 +207,57 @@ public:
|
||||
void arwAnime();
|
||||
void dotAnimeInit();
|
||||
void dotAnime();
|
||||
void changeFont(JUTFont*);
|
||||
void setTextPosition(u8);
|
||||
void createScreen();
|
||||
void move();
|
||||
void draw();
|
||||
|
||||
/* 0x004 */ JKRExpHeap* mHeap;
|
||||
/* 0x008 */ sub_mesg_class* mMesg;
|
||||
/* 0x00C */ J2DScreen* scrn;
|
||||
/* 0x010 */ JUTFont* field_0x10;
|
||||
/* 0x014 */ JUTFont* field_0x14;
|
||||
/* 0x018 */ fopMsgM_pane_class field_0x18;
|
||||
/* 0x050 */ fopMsgM_pane_class field_0x50;
|
||||
/* 0x088 */ fopMsgM_pane_class field_0x88[4];
|
||||
/* 0x168 */ fopMsgM_pane_class field_0x168;
|
||||
/* 0x1A0 */ u8 field_0x1a0[0x1A4 - 0x1A0];
|
||||
/* 0x1A4 */ int field_0x1a4;
|
||||
/* 0x1A8 */ s16 field_0x1a8;
|
||||
/* 0x1AA */ u8 field_0x1aa[0x1AC - 0x1AA];
|
||||
/* 0x1AC */ JUtility::TColor field_0x1ac;
|
||||
/* 0x1B0 */ JUtility::TColor field_0x1b0;
|
||||
};
|
||||
|
||||
class dMesg_screenDataTalk_c {
|
||||
class dMesg_screenDataTalk_c : public dMesg_screenData_c {
|
||||
public:
|
||||
~dMesg_screenDataTalk_c();
|
||||
void createScreen();
|
||||
void changeFont(JUTFont*);
|
||||
void openAnime();
|
||||
void closeAnime();
|
||||
void setTextPosition(u8);
|
||||
void draw();
|
||||
virtual ~dMesg_screenDataTalk_c() {}
|
||||
virtual void createScreen();
|
||||
virtual void changeFont(JUTFont*);
|
||||
virtual bool openAnime();
|
||||
virtual bool closeAnime();
|
||||
virtual void setTextPosition(u8);
|
||||
virtual void draw();
|
||||
|
||||
/* 0x1B4*/ f32 field_0x1b4;
|
||||
};
|
||||
|
||||
class dMesg_screenDataItem_c {
|
||||
class dMesg_screenDataItem_c : public dMesg_screenData_c {
|
||||
public:
|
||||
~dMesg_screenDataItem_c();
|
||||
void createScreen();
|
||||
void changeFont(JUTFont*);
|
||||
void deleteScreen();
|
||||
void openAnime();
|
||||
void closeAnime();
|
||||
void move();
|
||||
void draw();
|
||||
virtual ~dMesg_screenDataItem_c() {}
|
||||
virtual void createScreen();
|
||||
virtual void changeFont(JUTFont*);
|
||||
virtual void deleteScreen();
|
||||
virtual bool openAnime();
|
||||
virtual bool closeAnime();
|
||||
virtual void move();
|
||||
virtual void draw();
|
||||
void ringMove();
|
||||
void lightMove();
|
||||
void cornerMove();
|
||||
|
||||
/* 0x1B4 */ fopMsgM_pane_class field_0x1b4;
|
||||
/* 0x1EC */ fopMsgM_pane_class field_0x1ec;
|
||||
/* 0x224 */ fopMsgM_pane_class field_0x224[8];
|
||||
/* 0x3E4 */ JPABaseEmitter* field_0x3e4;
|
||||
/* 0x3E8 */ f32 field_0x3e8;
|
||||
/* 0x3EC */ ResTIMG* texBuffer;
|
||||
};
|
||||
|
||||
#endif /* D_MESG_H */
|
||||
|
||||
@@ -348,10 +348,14 @@ void fopMsgM_tactMsgFlagOff();
|
||||
bool fopMsgM_tactMsgFlagCheck();
|
||||
|
||||
void fopMsgM_blendInit(fopMsgM_pane_class* i_this, const char* data);
|
||||
void fopMsgM_blendInit(J2DPicture* pic, const char* data);
|
||||
u32 fopMsgM_getColorTable(u16 param_1);
|
||||
void fopMsgM_blendDraw(fopMsgM_pane_class* i_this, const char* data);
|
||||
void fopMsgM_blendDraw(J2DPicture* pic, const char* data);
|
||||
void fopMsgM_setFontsizeCenter(char* param_1, char* param_2, char* param_3, char* param_4, int param_5, int param_6);
|
||||
void fopMsgM_setFontsizeCenter2(char* a, char* b, char* c, char* d, int, int size, int, int);
|
||||
|
||||
void fopMsgM_outFontSet(J2DPicture*, J2DPicture*, s16*, u32, u8);
|
||||
void fopMsgM_outFontDraw(J2DPicture*, J2DPicture*, int, int, int, s16*, u8, u8);
|
||||
|
||||
#endif /* F_OP_MSG_MNG_H */
|
||||
|
||||
@@ -385,4 +385,12 @@ inline void mDoAud_registWindowPos(Vec* param_0) {
|
||||
mDoAud_zelAudio_c::getInterface()->registWindowPos(param_0);
|
||||
}
|
||||
|
||||
inline void mDoAud_talkIn() {
|
||||
mDoAud_zelAudio_c::getInterface()->talkIn();
|
||||
}
|
||||
|
||||
inline void mDoAud_talkOut() {
|
||||
mDoAud_zelAudio_c::getInterface()->talkOut();
|
||||
}
|
||||
|
||||
#endif /* M_DO_AUDIO_H */
|
||||
|
||||
@@ -1532,8 +1532,16 @@ void JAIZelBasic::bgmMute(JAISound**, u32, s32, u32) {
|
||||
}
|
||||
|
||||
/* 802ABBD0-802ABC3C .text checkStreamPlaying__11JAIZelBasicFUl */
|
||||
int JAIZelBasic::checkStreamPlaying(u32) {
|
||||
int JAIZelBasic::checkStreamPlaying(u32 param_1) {
|
||||
/* Nonmatching */
|
||||
JAISound* sound = JAInter::StreamMgr::streamUpdate->mpSound;
|
||||
if (!sound) {
|
||||
return false;
|
||||
}
|
||||
if (JAInter::StreamLib::getPlayingFlag() == 0) {
|
||||
return false;
|
||||
}
|
||||
return param_1 == sound->mSoundID;
|
||||
}
|
||||
|
||||
/* 802ABC3C-802ABC88 .text stWaterLevelUp__11JAIZelBasicFv */
|
||||
|
||||
@@ -149,7 +149,7 @@ void TProcessor::on_tag_() {
|
||||
}
|
||||
|
||||
/* 8029F120-8029F248 .text do_tag___Q28JMessage10TProcessorFUlPCvUl */
|
||||
bool TProcessor::do_tag_(u32 tag, const void* data, u32 size) {
|
||||
void TProcessor::do_tag_(u32 tag, const void* data, u32 size) {
|
||||
u16 code = data::getTagCode(tag);
|
||||
u8 group = data::getTagGroup(tag);
|
||||
|
||||
@@ -421,7 +421,7 @@ void TSequenceProcessor::do_end_() {
|
||||
}
|
||||
|
||||
/* 8029F8C8-8029F9D4 .text do_tag___Q28JMessage18TSequenceProcessorFUlPCvUl */
|
||||
bool TSequenceProcessor::do_tag_(u32 tag, const void* data, u32 size) {
|
||||
void TSequenceProcessor::do_tag_(u32 tag, const void* data, u32 size) {
|
||||
const char* datap = (const char*)data;
|
||||
u16 code = data::getTagCode(tag);
|
||||
u8 group = data::getTagGroup(tag);
|
||||
@@ -490,14 +490,14 @@ bool TSequenceProcessor::process_jump_(TSequenceProcessor* proc) {
|
||||
bool TSequenceProcessor::process_branch_limited_(TSequenceProcessor* proc, u32 choice) {
|
||||
/* Nonmatching */
|
||||
BranchCallBackWork* work = (BranchCallBackWork*) &proc->mStatusData.mCallBackWork;
|
||||
process_setMessage_index_(proc->mControl, ((u16*)work->mTable)[choice]);
|
||||
return process_setMessage_index_(proc->mControl, ((u16*)work->mTable)[choice]);
|
||||
}
|
||||
|
||||
/* 8029FAB8-8029FAE8 .text process_branch___Q28JMessage18TSequenceProcessorFPQ28JMessage18TSequenceProcessorUl */
|
||||
bool TSequenceProcessor::process_branch_(TSequenceProcessor* proc, u32 choice) {
|
||||
/* Nonmatching */
|
||||
BranchCallBackWork* work = (BranchCallBackWork*) &proc->mStatusData.mCallBackWork;
|
||||
process_setMessage_code_(proc->mControl, ((u32*)work->mTable)[choice]);
|
||||
return process_setMessage_code_(proc->mControl, ((u32*)work->mTable)[choice]);
|
||||
}
|
||||
|
||||
/* 8029FAE8-8029FB20 .text __ct__Q28JMessage19TRenderingProcessorFPQ28JMessage8TControl */
|
||||
@@ -538,7 +538,7 @@ void TRenderingProcessor::do_end_() {
|
||||
}
|
||||
|
||||
/* 8029FC50-8029FC84 .text do_tag___Q28JMessage19TRenderingProcessorFUlPCvUl */
|
||||
bool TRenderingProcessor::do_tag_(u32 tag, const void* data, u32 size) {
|
||||
void TRenderingProcessor::do_tag_(u32 tag, const void* data, u32 size) {
|
||||
u8 group = data::getTagGroup(tag);
|
||||
|
||||
switch (group) {
|
||||
|
||||
+1935
-151
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user