Jump to content
  • 0

I challenge everybody...


john_smith_account
 Share

Question

Recommended Posts

  • 0

Kinda a long shot, but you might see if you can find anything in the code for the Beamos that makes it aim at link. Use that as a reference. 

You know, I was just thinking about that this morning...

 

You also have 3 planes to work with... unlike 2D which only has one. Your (X,Y), (X,Z) and (Z,Y). That should be useful to know how many angles you're dealing with.

 

When I was messing in RAM in my "Link Rotations" video, I saw a good list of degree values, and I think 0x8000 is 360 degrees.

Link to comment
Share on other sites

  • 0

There's at least one inverse trigonometric function (arctan I think) there but you don't even need to use it (directly) to get the actor to face Link. There is a function that will return the rotation value you need for any actor to face another actor, 80078068. Its arguments are: a0 = (pointer to current actor + 0x24), a1 = (pointer to target actor + 0x38). Take the return value of that function and store it to 0xB6 in your actor's RAM structure and it will face the target actor at all times.

 

If you want more detail on how it works, the game basically gets a direction vector from the x and z positions of the actors and works out the angle using the ratio and size of the two components and the direction of the vector. The function it uses to do that doesn't figure out the angle directly, it just converts the (magnitude of the) ratio into an index it uses to look up a result from a table (8012D310), which it then adds or subtracts numbers from to get the right direction (inverse trigonometric functions aren't 1 to 1).

  • Like 3
Link to comment
Share on other sites

  • 0

I love you, DeathBasket.

 

Well, now that I have aiming working correctly, I have encountered one last problem: collision. While implementing function calls to initialize collision (DeathBasket, you sent me a PM on this a while ago), nOVL simply crashes when I try converting the ELF to an overlay. There are no error codes, etc; nOVL just "stops responding".

Link to comment
Share on other sites

  • 0

I would love to have the modified actor Jason777 when it's ready. I have an idea where I will be using it.

 

I think I will make it a code stub, or expand another actor to work with it. I don't want it to be made into a totem pole, I want the raw code if it works.

Link to comment
Share on other sites

  • 0

Honestly, I think I may have to straight-up write the actor in assembly; I'm experiencing issues with both nOVL and GCC's MIPS C compiler that I think can be avoided if I just choose not to write it in C. I think that in the end it may be an issue with nOVL and relocation data so I don't know if I'll be able to fix it entirely.

 

Maybe there's something I'm not doing correctly here... Any of you who are experienced in writing actors in C might be able to find somewhere where I messed up. There are a lot of commented out things that I was mainly using for testing purposes. For some reason whenever I try to save the pointer that is returned by func_80032458, spawning no longer works correctly. There's also the issue of nOVL crashing whenever I try updating collision sphere placement...

 

 

 

#include <zelda64.h>#include <actor.h>#include <mips.h>/* ----- Actor-specific values ----- */#define EXAMPLE_ACT		0x0082		/* Actor 0x0082 is the BETA vase entry so it can be used for testing purposes */#define EXAMPLE_OBJ		0x0086		/* Object 0x0086 is the BETA vase entry so it can be used for testing purposes */#define EN_AROW_TRAP_ACT	0x0081		/* En_Arow_Trap's actor # *//* ----- General in-game functions which set up an actor ----- */extern void func_8002d62c(struct z64_actor_t *, u32);									/* Sets scale */extern void func_8002b1e0(void *, u32, void *, u32);									/* I don't know what this function does yet */extern void func_80035260(void *, u32);											/* Sets display list to render */extern void func_8005dc4c(void *, void *, void *);									/* Sets where to draw collision */extern void func_8005c364(void *, void *);										/* Helps initialize collision */ extern void func_8005c4ac(void *, void *, struct z64_actor_t *, u32 *);							/* Helps initialize collision */extern u16 func_80078068(void *, void*);										/* Returns rotation value to face a specified actor */extern struct z64_actor_t * func_80032458(void *, void *, void *, u16, f32, f32, f32, u16, u16, u16, u16);				/* ActorSpawn but for different unknown purposes... possibly for scaling *///extern u32 func_80031f50(u32, u32, u16, f32, f32, f32, u16, u16, u16, u16);					/* Regular ActorSpawn */extern char obj_8002B5EC;	/* I'm guessing this is where object 0x0086 is always loaded into the RAM? *//* ----- These are the actual user-defined functions which vary from actor to actor ----- */extern void example_init(struct z64_actor_t * a, void * o);	/* Initialization */			extern void example_null(struct z64_actor_t * a, void * o);	/* NULL */extern void example_main(struct z64_actor_t * a, void * o);	/* Main AI */extern void example_render(struct z64_actor_t * a, void * o);	/* Model Rendering *//* ----- Actor header ----- */MK_AHEAD(	En_Arow_Trap_Util, 	/* Actor Name: Masks */	EXAMPLE_ACT, 		/* Actor #: 0x0082 */	6,			/* Actor Type: Item */	0, 			/* Actor Status... Whatever the hell that is */	0x10,			/* Unknown */ 	EXAMPLE_OBJ,		/* Object #: 0x0086 */ 	0x14C, 			/* Unknown */	example_init,		/* Address of Initialization Function */ 	example_null, 		/* Address of NULL Function */	example_main, 		/* Address of Main AI Function */	example_render		/* Address of Render/Display Function */);u32 Collision[] = {0x0a000039, 0x20010000, 0, 0, 0, 0, 0, 0x00000100, 0x00140040, 0, 0};struct z64_actor_t * En_Arow_Trap;/* ----- Initialization/Constructor function ----- */void example_init(struct z64_actor_t * a, void * o){	/* Set actor scale of ovl_en_example's object (IEEE 754 float) */	func_8002d62c(a, 0x3C23D70A);	/* Set spawn XYZ coordinates to current XYZ coordinates? */	//a->coords_3 = a->coords_2;	/* Allocate actor and its object? I really don't know */	//func_8002b1e0(AADDR(a, 0x00B4), 0, &obj_8002B5EC, 0x40C00000);	/* Set up collision */	//func_8005c364(o, AADDR(a, 0x194));        //func_8005c4ac(o, AADDR(a, 0x194), a, Collision);	/* Spawn En_Arow_Trap at current XYZ coordinates and Y rotation... I was using the bomb for testing purposes */	func_80032458((void*)(0x80213C44), AADDR(a, 0x0), o, 0x0010, AVAL(a, f32, 0x24), AVAL(a, f32, 0x28), AVAL(a, f32, 0x2C), 0, AVAL(a, u16, 0xB6), 0, 0xFFFF);	//En_Arow_Trap = func_80032458((void*)(0x80213C44), a, (void*)(0x80212020), 0x0081, AVAL(a, f32, 0x24), AVAL(a, f32, 0x28), AVAL(a, f32, 0x2C), 0, AVAL(a, u16, 0xB6), 0, 0xFFFF);	//func_80031f50(0x80213C44, 0x80212020, 0x0010, AVAL(a, f32, 0x24), AVAL(a, f32, 0x28), AVAL(a, f32, 0x2C), 0, 0, 0, 0xFFFF);}/* ----- NULL function ----- */void example_null(struct z64_actor_t * a, void * o){	/* NULL function: for some reason it's necessary to have */	return;}/* ----- Rendering/Display function ----- */void example_render(struct z64_actor_t * a, void * o){	/* BETA Vase model */	func_80035260(o, 0x06000000);	/* Update collision sphere */	/*	AVAL(a, u16, 0x1DA) = (u16)AVAL(a, f32, 0x24);	AVAL(a, u16, 0x1DC) = (u16)AVAL(a, f32, 0x28);        AVAL(a, u16, 0x1DE) = (u16)AVAL(a, f32, 0x2C);        func_8005dc4c(o, (void*)(0x80212020 + 0x11E60), AADDR(a, 0x194));	*/}/* ----- Main AI function ----- */void example_main(struct z64_actor_t * a, void * o){	struct z64_actor_t * Link = (void*)LINK;	//a->coords_2 = Link->coords_2; // This works...	// Incorrect usage of pointers...	//(*(f32*)(a + 0x24)) = (*(f32*)(Link + 0x24)); // This doesn't...	//(*(f32*)(a + 0x28)) = (*(f32*)(Link + 0x28)); // Or this...	//(*(f32*)(a + 0x2C)) = (*(f32*)(Link + 0x2C)); // Or this...	// Ah! I wasn't using pointers correctly 	//AVAL(a, f32, 0x24) = AVAL(Link, f32, 0x24); // Works! 	//AVAL(a, f32, 0x28) = AVAL(Link, f32, 0x28) + 50.0f; // And this!	//AVAL(a, f32, 0x2C) = AVAL(Link, f32, 0x2C); // And this!	/* Copy Link's rotation... */	//AVAL(a, u16, 0xB4) = AVAL(Link, u16, 0xB4);	//AVAL(a, u16, 0xB6) = AVAL(Link, u16, 0xB6);	//AVAL(a, u16, 0xB8) = AVAL(Link, u16, 0xB8);		/* Have actor face Link... */	AVAL(a, u16, 0xB6) = func_80078068(AADDR(a, 0x24), AADDR(Link, 0x38));	//AVAL(En_Arow_Trap, u16, 0xB6) = AVAL(a, u16, 0xB6);	}

 

 

This is where it fucks up:

 

 

Here:

// Simply uncommenting this line of code causes spawning to mess up and Link can't shoot arrows or pull out bombs, etc.En_Arow_Trap = func_80032458((void*)(0x80213C44), a, (void*)(0x80212020), 0x0081, AVAL(a, f32, 0x24), AVAL(a, f32, 0x28), AVAL(a, f32, 0x2C), 0, AVAL(a, u16, 0xB6), 0, 0xFFFF);
And here:

// nOVL just crashes.../* Update collision sphere */	AVAL(a, u16, 0x1DA) = (u16)AVAL(a, f32, 0x24);	AVAL(a, u16, 0x1DC) = (u16)AVAL(a, f32, 0x28);        AVAL(a, u16, 0x1DE) = (u16)AVAL(a, f32, 0x2C);        func_8005dc4c(o, (void*)(0x80212020 + 0x11E60), AADDR(a, 0x194));}

 

 

Here are macros that one may need to know:

 

 

/* Get a value of arbitrary type from any address in the actor *//* Broken?#define AVAL(a,t,o)          (                                *((t)((u8*)(a) + (o)))   )*//* Fixed? I wasn't sure if the "t" value was on purpose */#define AVAL(a,t,o)          (                                *((t*)((u8*)(a) + (o)))   )/* Get the address */#define AADDR(a,o)           (                                (void*)((u8*)(a)+(o))    )

 

 

... And here's the modified en_arow_trap actor with its timer removed (for those who care):

 

 

#include "mips.h"	.set		noreorder	.set		noat	.text# Entry point: 0x809B37D0## NAME      VSTART       VEND         SIZE# .text     0x809B37D0   0x809B38D0   256# .data     0x809B38D0   0x809B38F0   32# .rodata   0x809B38F0   0x809B38F0   0# .bss      0x809B38F0   0x809B38F0   0data_809B37D0:	addiu           $sp,$sp,-24 // make space on stack	sw              a1,28($sp) // save global context	sw              $ra,20($sp) // save return address	lui             a1,0x3c23 	ori             a1,a1,0xd70a // A1 = 0.01f	jal             set_actor_size	sw              a0,24($sp) // save RAM actor pointer	lw              a0,24($sp) // restore RAM actor pointer	li              t6,80 // T6 = 80 (0x50)	lw              t8,36(a0) // T8 = Actor X position	lw              t7,40(a0) // T7 = Actor Y position	sw              $zero,332(a0) // AVAL(a, u32, 0x14C) = NULL	sw              t8,56(a0) // AVAL(a, u32, 0x38) = Actor X position	lw              t8,44(a0) // T8 = Actor Z position	sw              t6,336(a0) // AVAL(a, u32, 0x150) = 80	sw              t7,60(a0) // AVAL(a, u32, 0x3C) = Actor Y position	sw              t8,64(a0) // AVAL(a, u32, 0x40) = Actor Z position	lw              $ra,20($sp) // restore return address	addiu           $sp,$sp,24 // fix stack	jr              $ra // return	nop // nothingdata_809B3824:	sw              a0,0($sp) // save actor pointer? It's an unusal place to save on the stack...	jr              $ra // return	sw              a1,4($sp) // save global context? It's an unusal place to save on the stack...data_809B3830:	addiu           $sp,$sp,-56 // make space on stack	sw              $ra,52($sp) // save return address	sw              s0,48($sp) // save S0	lui             $at,0x43c8 // AT = 400.0f 	mtc1		$at,$f4 // F4 = 400.0f	lwc1            $f6,144(a0) // F6 = AVAL(a, f32, 0x90);	or              s0,a0,$zero // S0 = RAM actor pointer/* This right here is probably the proximity check Airikita was talking about */	c.le.s		$f6,$f4 // (F6 <= F4) ? FP = 1 : FP = 0	nop // nothing	bc1fl		$L000000 // if (FP == 0) goto L000000	lw              $ra,52($sp) // { restore return address }	lw              t6,336(a0) // T6 = AVAL (a, u32, 0x150)	addiu           t7,t6,-1 // T7 = T6 - 1	/* Hack starts here... removing timer */	/* bne             t7,$zero,$L000001 // if (T7 != 0) goto L000001 */	sw              t7,336(a0) // Delay Slot: AVAL(a, u32, 0x150) = T7	lwc1            $f8,40(s0) // F8 = Actor Y position	lw              a3,36(s0) // A3 = Actor X position	li              t2,-1 // T2 = 0xFFFF	swc1            $f8,16($sp) // SP + 0x10 = Y position 	lwc1            $f10,44(s0) // F10 = Actor Z position	addiu           a0,a1,7204 // A1 = 80213C44	li              a2,22 // A2 = 22 (0x16)	swc1            $f10,20($sp) // SP + 0x14 = Z position	lh              t9,180(s0) // T9 = Actor X rotation	sw              t9,24($sp) // SP + 0x18 = X rotation	lh              t0,182(s0) // T0 = Actor Y rotation	sw              t0,28($sp) // SP + 0x1C = Y rotation	lh              t1,184(s0) // T1 = Actor Z rotation	sw              t2,36($sp) // SP + 0x24 = Variable	jal             ActorSpawn // ActorSpawn();	sw              t1,32($sp) // Delay Slot: SP + 0x20 = Z rotation	li              t3,80 // T3 = 80 (0x50)	sw              t3,336(s0) // AVAL(a, u32, 0x150) = 80$L000001:	lw              $ra,52($sp) // restore return address$L000000:	lw              s0,48($sp) // restore	addiu           $sp,$sp,56 // fix stack	jr              $ra // return	nop // nothing	nop // nothing	nop // nothing	.section		.data	.byte 0x00	.byte 0x81	.byte 0x06	.byte 0x00	.byte 0x00	.byte 0x00	.byte 0x00	.byte 0x10	.byte 0x00	.byte 0x01	.byte 0x00	.byte 0x00	.byte 0x00	.byte 0x00	.byte 0x01	.byte 0x54	.word data_809B37D0 // Initialization	.word data_809B3824 // ? -- It only saves A0 and A1 at strange places on the stack	.word data_809B3830 // MAIN	.byte 0x00	.byte 0x00	.byte 0x00	.byte 0x00# 0x809B38F0	.bss

 

Link to comment
Share on other sites

  • 0

Try to avoid using variables in that manner (Collision and En_Arrow_Trap) - they end up in the .data section. Instead, use the AVAL macros on whatever space isn't used in the actor panel.

 

EDIT: Also try running nOVL with maximum verbosity - command line -vvv option. It may give you more insight as to why it is crashing.

Link to comment
Share on other sites

  • 0

I'm starting to think we just need to make an actor spawn these arrows instead, not the arrow trap. This is obviously doing no good... anyways, I think the variable for the arrows to hurt Link were 0030 or 0050. I forget as I have been very busy the past few weeks.

Link to comment
Share on other sites

  • 0

I'm starting to think we just need to make an actor spawn these arrows instead, not the arrow trap. This is obviously doing no good... anyways, I think the variable for the arrows to hurt Link were 0030 or 0050. I forget as I have been very busy the past few weeks.

That's what I was originally planning... I was going to make a few modifications here and there to en_arow_trap (remove the timer, remove proximity check) and then I was going to write a custom actor with collision, aiming, and a model which spawned en_arow_trap through its initialization function. Currently, both are done but the custom actor is running into some problems upon compiling.

 

EDIT: Alright the problem with collision is that nOVL seems to be handling virtual addresses as out-of-bounds memory addresses. I was under the impression that it should only be doing that for addresses that are less than or equal to 0x807FFFFF (within the range of absolute RAM addresses). As for spawning, I don't quite know why that isn't working correctly, yet.

 

As you can see in the picture below, nOVL starts by looking for relocations in the main function and then proceeds to look for more in the display function. Upon finishing its search it encounters a function call to func_8005dc4c and crashes upon scanning the delay slot. I say the delay slot because it follows immediately after the function call... that's a guess though.

 

Posted Image

 

Yeah... writing the custom actor in assembly seems like the only option at this point.

 

EDIT 2: Funny. I commented out one of the AVALs in the display function and the actor compiled. However, looking at the log given off by nOVL still shows how messed up it is:

 

Posted Image

 

Well, apparently the function prototype for the spawning function was incorrect. Spawning may be possibly fixed now; nOVL recognizes the function call to 0x80032458, but I have yet to test it.

 

EDIT 3: Alright well it turns out that spawning was working correctly but XYZ placement was not. The only thing that this actor lacks is collision... How does a progress video sound to you all?

Link to comment
Share on other sites

  • 0

Well, I finally got off my ass today and rewrote the actor in assembly just to make sure that it wasn't a problem with my coding... I'm happy to say that the actor works exactly as intended!

 

I will link to a new topic in this thread later today with the custom actor, its source, as well as other modifications I made to get everything working (including the original C actor that I ended up rewriting). Collision will be a part of a later release. In the meantime, I'll be throwing together a model and making a video after I'm done running errands and doing real-life shit today.

 

Happy day :)

Link to comment
Share on other sites

  • 0

From what I could tell, it changes the textures... I'm guessing... you might be right about the shiny coat, but the name makes me curious...

 

No spawning or model rendering.

 

EDIT:

I spawned it from Jabu Jabu during the cutscene when Jabu swallows Link, replacing the sparklies that appear to represent the air being sucked into Jabu's mouth. It doesn't crash, but it doesn't seem to do anything.

 

When I observed the actor, there are no spare object groups, just 0040. It's possible it's part of Jabu Jabu, but it has no significance other than possibly what is assumed... a possible shader to Lord Jabu Jabu? I'm tempted to attach this code to Lord Jabu Jabu somehow... perhaps its beta code doesn't work in this game anymore, or it just needs to be Linked it Jabu's model. It could be possible that it was used to render Lord Jabu Jabu's model before it was loaded into the map.

 

That being said, I'll have to dig through it, and attempt expanding Jabu's AI to insert the code, reconfiguring it to work. If I finish my work early today, I'll look into it tonight.

Link to comment
Share on other sites

 Share

×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use.