Use the code to your heart's content. No need to add me in credits unless you really want to. Replace camera_move() function with the one below to fix the spinning problem. The spinning problem occured when the camera went through the roof. The new function should stop the camera going through the roof when you move the mouse up. If the player dissapears under a ledge and the camera is above the ledge, the spinning problem will occur again. You can make your levels around this by making sure the camera height is capped at a lower height, and making sure the player wont dissapear under a WED block. The camera works fine with buildings, it's when you have a tunnel or a roof and the camera is above it.

You can also use the same camera function, replace the "my" pointer with any other entity pointer. Then have a function which changes which entity possesses the pointer and the camera will move smoothly to that entity. This is useful in Turn Based fights. You select enemy and the selected enemy can be assigned the pointer, the camera will move to that enemy smoothly.

-------------------------------------------------------------
FUNCTION camera_move() {
my.skill68 = 1000;
trace_mode = ignore_me + ignore_passable + ignore_models + ignore_maps; //trace above player to see if there is a wall above
result = trace (vector(camera.x,camera.y,my.z + 70),vector(camera.x,camera.y,my.z + 2000));
IF (result > 0) { IF (camera_height_main > result - 20) { camera_height_main = result -20; my.skill68 = camera_height_main; } }

my.z += 15; //temporarily changed so that camera focusus slightly above middle

vec_set(temp.x,vector(my.x - fcos(camera.pan,camera_radius),my.y - fsin(camera.pan,camera_radius),camera.z));
trace_mode = ignore_me + ignore_passable + ignore_models + ignore_maps;
result = trace (my.x,temp.x);
IF (result > 0) {
result = sqrt(((target.x - my.x)*(target.x - my.x))+((target.y - my.y)*(target.y - my.y)));
camera_pan_to += camera_pan_direction * 15 * time;
IF (my.force_z < -5) {
camera_height_main += 80 * time;
camera_height += 80 * time;
IF (camera_height_main > my.skill68) { camera_height_main = my.skill68; }
IF (camera_height > camera_height_main) { camera_height = camera_height_main; }
}
} ELSE {
result = camera_radius;
}
IF (result < camera_radius) {
camera_radius_move_to = result;
} ELSE {
camera_radius_move_to = camera_radius;
}

IF (camera_height > camera_height_main) {
camera_height -= 15 * time;
IF (camera_height < camera_height_main) { camera_height = camera_height_main; }
}
IF (camera_height < camera_height_main) {
camera_height += 15 * time;
IF (camera_height > camera_height_main) { camera_height = camera_height_main; }
}

IF (camera_radius_move_to < 15) { camera_radius_move_to = 15; }

vec_set(temp,my.x);
vec_sub(temp,camera.x);
vec_to_angle(temp.pan,temp);
camera_tilt_to = temp.tilt + camera_tilt_offset; //this causes the camera to tilt towards the player

camera_distance = camera_radius_move_to;
my.z -= 15; //temporarily changed so that camera focusus slightly above middle

vec_set(camera_move_to.x,vector(my.x - fcos(camera.pan,camera_distance),my.y - fsin(camera.pan,camera_distance),my.z + camera_height));

camera_tilt_force = (camera.tilt - camera_tilt_to) / -3;
IF (camera_tilt_force > 0) {
camera_tilt_force = min(camera_tilt_force,3);
} ELSE {
camera_tilt_force = max(camera_tilt_force,-3);
}
camera_tilt_velocity = 0.5*camera_tilt_force + max(1-0.5*0.7,0) * camera_tilt_velocity;
camera.tilt += camera_tilt_velocity * TIME;

camera_pan_force = (camera.pan - camera_pan_to) / -3;
IF (camera_pan_force > 0) {
camera_pan_force = min(camera_pan_force,10);
} ELSE {
camera_pan_force = max(camera_pan_force,-10);
}
camera_pan_velocity = 0.5*camera_pan_force + max(1-0.5*0.7,0) * camera_pan_velocity;
camera.pan += camera_pan_velocity * TIME;

IF (abs(camera.x - camera_move_to.x) > 2) {
camera_force.x = (camera.x - camera_move_to.x) / -4;
} ELSE {
camera_force.x = 0;
camera_velocity.x = 0;
}
IF (abs(camera.y - camera_move_to.y) > 2) {
camera_force.y = (camera.y - camera_move_to.y) / -4;
} ELSE {
camera_force.y = 0;
camera_velocity.y = 0;
}
IF (abs(camera.y - camera_move_to.z) > 2) {
camera_force.z = (camera.z - camera_move_to.z) / -12;
} ELSE {
camera_force.z = 0;
camera_velocity.z = 0;
}

IF (key_w == 1 && key_d == 1) || (key_w == 1 && key_a == 1) || (key_s == 1 && key_d == 1) || (key_s == 1 && key_a == 1) {
camera_force.x /= 1.5;
camera_force.y /= 1.5;
}

camera_velocity.x = 0.5*camera_force.x + max(1-0.5*0.7,0)*camera_velocity.x;
camera_velocity.y = 0.5*camera_force.y + max(1-0.5*0.7,0)*camera_velocity.y;
camera_velocity.z = 0.5*camera_force.z + max(1-0.5*0.7,0)*camera_velocity.z;
camera.x += TIME * camera_velocity.x;
camera.y += TIME * camera_velocity.y;
camera.z += TIME * camera_velocity.z;
}